-sof


                         MidiShare
                         Developer Documentation
                         vers. 1.67
                         English Alpha draft



 INTRODUCTION


Foreword


MidiShare is a multi-tasking, real-time software environment,
specially devised for the developing of MIDI applications with
a triple target :

    To propose solutions to currently met problems when developing
    any MIDI application : MIDI communication, synchronisation and
    time management, task management and memory management.

    ?To enable the real-time and multi-tasking functioning of these
    applications, i.e. to enable the sharing of all the necessary
    resources and their simultaneous access.

    ?To make easier co-operation between independent MIDI applications
    by  proposing a real-time mechanism of inter-application
    communications.

The present document is intended for developers who wish to use
MidiShare for the writing of MIDI applications. They will find here
a complete description of all the MidiShare functions and procedures,
as well as all the data structures in use.

Yann Orlarey and Herv Lequay



OVERVIEW


 About MidiShare

 
The availability of multi-tasking operating systems such as
Multi-Finder, Unix and OS/2 on microcomputers is a decisive
advantage in many application areas and offers real gains in
term of power and ease of use.

Unfortunately, until now musicians have hardly benefited at all
from the advantages of such systems due to the lack of music
applications capable of running simultaneously in real  time on
a single machine. The internal layers of a Midi program often
make use of critical resources of the computer such as timers,
interrupts and serial link controllers which cannot be directly
shared by more than one application, in addition, even multi-tasking
operating systems are not generally a guarantee that applications
run in real time.

Midishare came into existence from this observation with the ambition
to provide the frame needed to develope musical applications in a
multi-tasks and real time context. When defining MidiShare, we have
tried to conciliate three aims :

?To propose solutions to the problems regularly met with in the
 development of all Midi applications.

?To permit the simultaneous running of these applications,
 especially as regards real-time routines and Midi communications.

?To allow for a co-operation between separately developed applications.

We are going to see how the various tools and services proposed by
MidiShare comply with these objectives.



Events Managing


The whole system is based on the notion of event. An event is a
dated entity possessing the informations for its own execution.
The applications developed with MidiShare heavily relie on events
to transmit and receive Midi messages but also to remember the tasks
to be carried out.

It is generally not possible to use the host Operating System Memory
Manager (MM) to deal with the allocation-deallocation of these events,
since it revealed unadapted to a real-time context, non reentrant and
inefficient, in terms of memory space when dealing with small zones
of a few bytes.

To make up for these lacks, MidiShare has its own dynamic memory
allocation module, adapted to real-time constraints. For example,
some functions permit to create or delete events (under interrupt too)
with an extremely brief and constant time response.
Moreover, these events can be accessed to and handled in a uniform
and orthogonal way by a small number of routines which take
automatically in charge the various memory structures (for, let us
say, a constant size Key On and a variable size System Exclusive).



Communicating


The second essential point is the communications achievement.
The applications running under Midishare are not in charge of the
communications physical execution but only deal with receiving and
sending high-level events, for instance, complete Midi messages.
In fact, MidiShare is internally in charge of translating events
into corresponding Midi bytes sequences. Each application receives
events into its own reception fifo. The application can consult
this fifo anytime, extract and process the events waiting for
treatment. Sending out events is easy as well. Stating the required
output time and event to be transmitted will be sufficient.

Midi multiple ports can of course be used. On some softwares,
Midi Channels are numbered from 0 to 31 so as to take into account
the two ports which can be used on Macintosh computers. We thought
preferable to separate these two informations. This way, each
Midishare event has a channel number from 0 to 15 and a port number
from 0 to 255; in the future, this will permit to deal with
numerous Midi lines.



Time managing


It is obvious that a precise time control is essential for music.
It is obvious too that according to the type of musical work
carried out, different time representations are needed; which is
why we chose the well-tried general solution consisting in an
absolute representation of time in milliseconds over which other
more musical representations can be built up by applications.

A 32 bits field defines the time for each MidiShare event. This
field mentions the arrival time for the events received by an
application or the required transmission time for events sent
out by an application.

The algorithm used to manage the events scheduling is of course
critical to the system's performances. Several methods have been
proposed. In this particular case, we have used an algorithm
developed at first by one of the authors for MidiLisp. This very
efficient algorithm ensures in all cases a bounded scheduling
and dispatching time for treated events.

MidiShare can be synchronised to external Midi Time Code. In this
case the MidiShare internal time unit accuratly follow the speed
variations of the external Midi Time Code. Midi applications can be
automatically informed when MidiShare start and stop being locked to
external Midi Time Code.



 Tasks managing
 

Not only Midi messages are managed by MidiShare. Actually, an
application having to remind a task to be done at a precise
moment, can send to itself a particular type of message containing
all the informations required for this task to be carried out.
When arrived at maturity, this internal event is set by MidiShare
in the application's reception fifo as if it were an external event.
The application's reception routine will then accomplish the required
task.

A second mechanism is implemented by MidiShare for tasks management.
It is much more procedural and actually, very similar to Moxie's
cause. It is in fact a delayed procedure call. For this to be done,
MidiShare collects all the call parameters, together with the address
of the routine to be called and generates a specific internal event.
When this event has come to maturity, MidiShare restores the
application context and actually deals with the call. It is to be
noted that this call is made under interrupts, which means that some
precautions have to be taken.

A third point related with tasks managing is the possibility for an
application to define a reception alarm. It is a routine whose
application gives MidiShare the address and which will be called
each time new events are received (see example). Alarm therefore
avoid an application having to consult periodically its reception
fifo. Moreover, being called under interrupts, they allow for very
efficient time responses.



Linking applications


As explained in the introduction, the reason for the creation of
MidiShare was to permit several independant Midi applications to
run simultaneously and to collaborate if necessary. This target
may initially seem paradoxical. On the one hand, giving very
application the impression to be the only user of the computer
and consequently lessening the applications common resources.
On the other hand, trying to connect these applications.

To isolate the applications was not a very difficult task. For
instance, as regards incoming Midi messages, each application
receives a different copy of them. Besides, every application
possesses its own filters and reception fifo. There are no problems
either to merge the various message transmissions, since they occur
at the logical level too. Finally, as regards time, all applications
refer to the same absolute clock in milliseconds, without having any
influence on it.

How can we now link these applications ? 
Many users undoubtedly experienced Midi informations
transfers, of musical sequences for instance, between two 
computers. We have taken over this idea and implemented 
inside MidiShare an internal real-time communication
mechanism between applications.

Let us take a concrete example: two applications, the first being an
echo generator, the second a sequencer. By default, these two
applications are connected to the actual Midi I/O. However, it is
quite possible to connect the output of the echo generator to the
input of the sequencer. Each application is not aware of the
connection change.

There is no constraint in the way to connect applications between
themselves. In particular, it is possible for an application to
have multiple sources and multiple destinations, or else to be
connected to itself (for example a sequencer recording itself).
Furthermore, these connections can be dynamically reconfigured while
the applications are running.



Opening and Closing MidiShare


First of all, an application must make sure that MidiShare is
in memory. This checking is done thanks to the MidiShare function.

Then, you must call the MidiOpen installation function. This routine
allows to record some information relative to the application
context (its name, the value of A5 register, etc...), to affect
a reception FIFO and to attribute a unique reference number to the
application.

As a counterpart to any MidiOpen call, the application must call the
MidiClose function before leaving, by giving its reference number as
an argument. MidiShare can thus be aware of the precise number of
active Midi applications. In theory, there is no objection to an
application doing several MidiOpen, under the condition it realizes
as many MidiClose. In all, there must not be more than 63
simultaneously opened Midi applications .

As long as no MidiOpen application is done, MidiShare is asleep and
has no influence on the computer functioning. Following the first
MidiOpen, MidiShare becomes active, it creates a task which will be
called by an interruption  every  millisecond,  then  it  initiates
Acia interruption vectors and registers corresponding to Midi ports.
MidiShare returns inactive after the last MidiClose.



Communications and Connections


For an application to be able to emit and receive events, it must
first connect to a source and a destination. In fact, MidiShare is
built on an internal communication mechanism allowing to exchange
in real-time Midi events between active application. An application
is like a black box, receiving a flow of events in entry and
producing a flow of events in output. This black box can be freely
connected to other black boxes, thus forming an arbitrarily complex
network. This is one of the major points of MidiShare,  that allows
a form of transparent and powerful collaboration between
applications otherwise totally independent.

"Real" Midi ins and outs are represented by a pseudo-application,
which is always refered to as number 0 and named "MidiShare", with
which you just have to connect to communicate with the outside.

The implementation of these connections is very simple.
The MidiConnect procedure allows to switch on or off a connection
between a source application and a destination application.
The MidiIsConnected function gives the state (on or off) of a
connection. There is no restriction to the establishing of
connections, an application can be source or destination as many
times as you wish. Loops are permitted.

In some special cases, it is important that an application may get
information on the other active MidiShare applications.
The MidiCountAppls function gives the number of open  Midi
applications. The MidiGetIndAppl function allows to know the
reference number of any application by giving its order number
(included between 1 and MidiCountAppls). It is also possible to
find the reference number of an application thanks to its name
using the MidiGetNamedAppl function. In the same way, knowing an
application reference number, it is possible to find its name using
the MidiGetName function. At last, the MidiSetName procedure allows
to change the name of an application.

To be able to write more easily some "meta-applications" for the
management of connections and other applications,  permanent
information on context modifications into MidiShare (opening of
new  applications,  changing connections, etc...)  is  highly
requested. To do so, you just have to define a context alarm thanks
to MidiSetApplAlarm and MidiGetApplAlarm routines. This alarm will
be automatically called by MidiShare to inform the application of
all the occured changes.



Sending and Receiving


Once the connections have been established, the application can
send and receive Midi events. Each application owns a reception
fifo  in which MidiShare puts a copy of the received events.
These come from other applications or from the different Midi ports
in activity. MidiShare can in theory handle up to 256 ports. The
implementation of Midi ports is controlled by the MidiSetPortState
and MidiGetPortState routines. These must be used with care since
they affect all the applications.

The MidiCountEvs function allows at any moment to know the number
of events waiting in the reception fifo. This number is only
limited by the memory size available for MidiShare. The events at
disposal are picked up by repeated appeals to MidiGetEv function.
The MidiAvailEv function is almost similar. It allows to read a
received event, while leaving it in the fifo. The MidiFlushEvs
procedure eliminates all the events on wait in the reception fifo.

The events received by an application are copies. The application
can therefore freely dispose of them without any repercussion on
the other applications. However, it must not forget to free them
when it no longer needs them.

Each application can select the events to be received by using a
filter. The filtering process is local to the application and has
no influence on the events received by the other applications.
The implementation of these filters is achieved by two routines :
MidiSetFilter and MidiGetFilter.

MidiShare drives an internal absolute clock on 32 bits which is
automatically switched on with the first MidiOpen and keeps running
until the last MidiClose. This clock is used to date (in milliseconds)
all the received events, as well as to specify the sending dates of
events to be transmitted. Moreover, it provides all the applications
with an absolute time reference. Its value can be read by the
MidiGetTime function.

Three routines allow to manage the transmissions. The MidiSendIm
procedure allows the immediate emission of an event. The MidiSend
and MidiSendAt procedures allow time delayed emissions, MidiShare
automatically taking in charge the effective emission at the
scheduled time (thanks to that mechanism, an application can easily
foresee emissions as accurately as to the millisecond and many days
in advance).

Once an event is sent (by the means of MidiSend, MidiSendAt or
MidiSendIm functions), it is no longer accessible by the
application. This event must no longer be refered to, under threat
of irremediable desorganisation of the system.

Example of what you must not do :

e = MidiNewEv (typeNote); /* Typical example of fatal error   */
MidiSendIm(myRefNum, e);  /* after having being sent,         */
f = MidiCopyEv(e);        /* the 'e' pointer no longer refers */
                          /* to any valid event               */



 Event Managing

 
The memory management of a standard application is generally achieved
by the computer "Memory Manager" (MM). The MM deals with dynamic
allocation and freeing memory blocks of arbitrarily length, as well
as memory compaction when necessary (excessive fragmentation of the
memory). Unfortunately, a traditional MM is proved unadapted to a
real time context. As a matter of fact :

? Only large blocks can be allocated efficiently by traditional MM.
  For example, the Macintosh MM needs 12 more bytes by allocated
  blocks, which is prohibitive for the very small group of bytes
  represented by a Midi event.

? The allocation time of a block is not constant, but depends on
  many factors, one of which being the fragmentation state of the
  memory. It can be very long if a memory compaction proves necessary.
  A traditional MM cannot guarantee the response time.

? A traditional MM is not re-entrant. No routine under interruption
  can  therefore  use  it  directly  or  undirectly, without
  irremediably desorganising the memory space.

To overcome these inadaptations, MidiShare holds its own memory
manager, adapted to the Midi event management and available under
interruption. MidiShare drives a group of events common to all the
applications. Each event has compulsory fields (date, channel, port,
type, etc...) and variable fields that depend of its type.

The allocation is very easily done by MidiNewEv function which
returns an event of a suitable type. The disallocation is as easily
done by the MidiFreeEv procedure.  An other way of allocating an
event is to duplicate an existing event by the MidiCopyEv function.
It is possible to know at every moment the available space left by
the MidiFreeSpace function.

The access to the compulsory fields of the event is directly done.
But the access to the variable fields is achieved thru the
MidiSetField and MidiGetField functions.

Some categories of events do not have a fixed number of fields.
Such is the case, for example, for the Exclusive System messages.
The MidiCountFields function gives the number of variable fields
of an event. The MidiAddField procedure allows to add a field at
the tail of an event of variable length.

For some special treatments, it may be useful to have access to the
basic functions of the memory manager. All the events managed by
MidiShare are implemented from fixed-sized cells (16 bytes).
Most of the events need just one cell. Others like the Exclusive
Systems use a variable number of cells linked to one another.
The user application normally does not have to worry about those
storage "details". Nevertheless, two functions are provided for
this low level memory management. The first one, MidiNewCell,
allows to allocate a simple cell. The second one, MidiFreeCell,
operates the reverse and de-allocates a cell.



Sequence Managing


MidiShare offers basic functionalities for the managing of
sequences  of time ordered events.  The  MidiNewSeq function
allocates a new sequence, empty at the start. The MidiAddSeq
procedure inserts an event into a sequence, maintaining the time
ordered dates.

The MidiApplySeq procedure is an iterator. It allows to apply a
procedure to all the events of a sequence.
The MidiClearSeq procedure frees the content of one sequence and
the MidiFreeSeq procedure frees the sequence and its content.



Real time tasks


The alarm concept is the basis of the MidiShare scheduling mechanism.
An alarm is a procedure whose address is sent to MidiShare by the
application. Then, MidiShare will call this procedure in real time
and often under interruption, to indicate the occurence of an event.

Each application can define two categories of alarms. The first
category is defined by the MidiSetApplAlarm procedure. It warns
of any change in the global context of MidiShare (see paragraph
"Communications and connections"). The second category is defined
by the MidiSetRcvAlarm procedure. It warns of the presence of new
events in the reception fifo. This alarm is always called under
interruption. Therefore, it must not use either directly or
indirectly the Macintosh Memory Manager. On the reverse, it can have
a free access to all the MidiShare functions (excepted MidiOpen and
MidiClose), in particular event management. It can also have access
to global variables of the application, because before the call,
MidiShare restaures its context register.

The Macintosh desk accesories cannot have global variables.
To make up for this drawback, The MidiSetInfo routine allows each
application to define a data area. This area remains accessible by
MidiGetInfo function, even during the alarm, and it also serves as
a global context to desk accessories and other purposes.

Once the RcvAlarm set, the application can easily organise its
real-time tasks thanks to the private event concept. On the
reverse of traditional Midi events, private events are meant for
Midi equipments, but are messages that the application sends to
itself. The application generally makes use of them to remember
a task to be done on a precise date.

Therefore, when the date of a private event falls due, MidiShare
sets the event into the application reception fifo, waiting there
to be picked up and handled in the same way as Midi events.

MidiShare implements a second mechanism to manage the tasks. This
is a time-delayed procedure call done thanks to MidiTask (or MidiCall)
and MidiDTask procedures. To acheive this call, MidiShare collects
all the call arguments, as well as the routine address to be called
and trigs a special event (TypeProcess or TypeDProcess). When a
TypeProcess event falls in, MidiShare restaures the application
context and does proceed to the call. On the reverse, when a
TypeDProcess event falls in, it is not processed, but set on a
waiting list belonging to the application. This one will have plenty
of time to process the waiting tasks when time comes, owing to
MidiCountDTasks (giving the number of tasks on wait) and
MidiExec1DTask (processing the next task on wait) functions.

As the MidiTasks are processed under interruption, they are not
allowed to call directly or indirectly the operating system.
The MidiDTasks allow to bypass this obstacle since the application
trigs their processing (generally in the main loop).

Under certain circumstances, "forgetting" a MidiTask or a
MidiDTask already launched but not yet processed, can be useful.
The MidiForgetTask function will be used for that purpose. An
application  MidiDTask  waiting  list  can  be  deleted  by
MidiFlushDTasks function.

At last, in order to make easier communication between the
application tasks and to manage accesses, shared between
certain variables, two ininterruptible, pointer-handling
routines can be used. The MidiReadSync function reads and sets
to NIL a memory address. The MidiWriteSync function updates an
address only if NIL.



Midi Time Code Synchronisation


MidiShare can be synchronised to external Midi Time Code (MTC) using
the MidiSetSyncMode function.

MidiSetSyncMode takes one parameter describing the chosen
synchronisation mode (internal or external) and the synchronisation
input port to be used. The synchronisation mode is global and all Midi
applications are affected. The function MidiGetSyncInfo provides
information about the synchronisation process.

When the synchronisation mode is set to internal (the default mode),
MidiShare is drived by an internal interrupt every millisecond.
The period of the MidiShare time unit is one millisecond. The function
MidiGetTime gives MidiShare internal time, the time elapsed since the
very first MidiOpen, expressed in milliseconds.

When the synchronisation mode is set to external, MidiShare starts
looking for incoming MTC. When enough MTCs are detected, MidiShare
becomes locked. It warns all the Midi applications, by calling their
ApplAlarm, if any, with code MidiSyncStart. A typical sequencer may
use this information to start playing a sequence according to the
position of the tape. The function MidiGetExtTime returns the position
of the tape in milliseconds.

When incoming MTC desappears, MidiShare became unlocked.
It automatically adjust its time unit to one millisecond and again
warns the midi applications via their ApplAlarm. with the code
MidiSyncStop. A typical sequencer application may decide to stop
playing its sequences.

While MidiShare is locked, it will maintains a constant offset between
its internal time and the external time (the time of the tape)
by automatically adjusting  the size of the time unit to follow the
speed variations of the incoming MTC. The size of the MidiShare time
unit will be exactly one millisecond when the MTC runs at its nominal
speed, it will increase when the MTC slow down and decrease when
the MTC speed up.

For example with a MTC format of 25 frames/second, one frame represents
40 milliseconds (1000/25). In this case MidiShare will adjust the size
ofits time unit in order to always have 40 time units per frame whatever
the actual speed of the incoming MTC is. Consequently, from the point
of view of a Midi application, the duration of one frame at
25 frames/seconds will always be 40 milliseconds.

The function MidiGetExtTime returns the external time (the time of the
tape expressed in milliseconds). While MidiShare is locked :
        MidiGetTime() - MidiGetExtTime() == constant offset
the difference between the MidiShare internal time and the tape time
expressed in millisecond is a constant.

Two functions are provided to make conversion between external and
internal time : MidiInt2ExtTime and MidiExt2IntTime. We have :
        MidiInt2ExtTime( MidiGetTime() ) == MidiGetExtTime()
        MidiExt2IntTime( MidiGetExtTime() ) == MidiGetTime()

Two additional functions, MidiTime2Smpte and MidiSmpte2Time, are
provided to make conversions between time expressed in millisecond
and SMPTE locations.

For example : MidiTime2Smpte( MidiGetExtTime(), 3, &loc ) set loc with
the current smpte location of the tape using smpte format 3
(30 frames / seconds).

These functions can be used to convert smpte locations from one format
to another. For example suppose we want to convert an smpte location
from its current format to 30 drop frame. we can write :
         MidiTime2Smpte( MidiSmpte2Time (&loc), 2, &loc);
where 2 means 30 drop frame.



Midi Event Structure 


Typology

The listing below presents the different types of MidiShare
handled events. This typology contains the whole of the standard
Midi messages, plus  specific messages such as the TypeNote
corresponding to a note with its duration ;  The TypeStream
corresponds to a series of arbitrary bytes, possibly including
data and status codes, sent directly without any processing; or
the TypePrivate that are application private messages.

All these codes may be used in the MidiNewEv function to allocate
an event of the desirable type and are accessible in  an event
evType field.

Name     		Code  	Comment 

TypeNote      	0    	pitch, vel and duration (16bits)
TypeKeyOn   	1    	pitch and vel
TypeKeyOff   	2    	pitch and vel
TypeKeyPress   	3    	pitch and press
TypeCtrlChange 	4    	ctrl and val
TypeProgChange 	5    	prog
TypeChanPress  	6    	press
TypePitchWheel 	7    	Lsb et Msb

TypeSongPos    	8    	Lsb et Msb
TypeSongSel    	9    	song
TypeClock      	10    -
TypeStart      	11    -
TypeContinu    	12    -
TypeStop       	13    -

TypeTune       	14    -
TypeActiveSens 	15    -
TypeReset      	16    -

TypeSysEx      	17    	data1..dataN
TypeStream     	18    	byte1..byteN

TypePrivate    	19..127  	arg1, arg2, arg3, arg4
TypeProcess    	128     	arg1, arg2, arg3, arg4
TypeDProcess  	129    	arg1, arg2, arg3, arg4
TypeQFrame     	130   	msg type (0..7) and value

TypeCtrl14b     	131
TypeNonRegParam 132
TypeRegParam    	133

TypeSeqNum      	134  	extended types from MidiFile 1.0
TypeText        	135
TypeCopyright   	136
TypeSeqName     	137
TypeInstrName   	138
TypeLyric       	139
TypeMarker      	140
TypeCuePoint    	141
TypeChanPrefix  	142
TypeEndTrack    	143
TypeTempo       	144
TypeSMPTEOffset 	145

TypeTimeSign    	146
TypeKeySign     	147
TypeSpecific    	148

TypeReserved    	149..254
TypeDead        	255    -



Internal structure


The MidiShare memory management is organised around fixed-sized
cells (16 bytes). All the events are composed of a header cell
that may be followed by one or many extension cells. Figure 1
describes the different fields composing the basic cell :

The Link field is a multi use link.
The date field includes the falling in date of the event
    (from 0 to 231-1).
The refNum field includes the application reference number
    sending this.
The evType field indicates the type of the event.
The Port field indicates the destination Midi port of the event.
The Chan field indicates the Midi channel of the event.

These six fields are always present and always have the same meaning,
whatever the type of the event. Their access can be direct. The info
part contains special fields the meaning of which depends on the type
of the event. In some cases, Info contain a pointer to one or several
extension cells. Direct access to the special fields is possible
provided one takes into account the differences of memory storage.
If not, the special functions MidiGetField and MidiSetField can be
used. These ones hide the event internal structure and allow to
have direct access to the special fields by specifying an index
between 0 and MidiCountFields - 1.

Midi messages with 0, 1 or 2 data bytes, use only one cell. These
two supplementary fields are accessible by the MidiGetField and
MidiSetField functions with index 0 and 1.

The notes have three more fields at their disposal :
0, 1 and 2 for pitch, velocity and duration. The access
functions MidiGetField and MidiSetField automatically detects
the 8, 16 or 32 bit fields.

System Exclusive type messages or Stream type messages include
variable number of fields. They use a structure build with elementary
cells linked one to another. The MidiGetField and MidiSetField
functions are able to follow the links giving access to data.
The MidiAddField procedure allows the addition of fields at the tail
of the message.

The private or internal type events need the use of an extension
cell. This one is composed of four 32 bits fields (from 0 to 3)
being able to contain any information left to the choice of the
application.



Midi Error Codes


List of the error codes returned by some MidiShare functions.

Name    		Code    	Comment

MIDIerrSpace    	-1    	No more space available in the freelist or
                      		too many applications
MIDIerrRefNum   	-2    	Bad reference number
MIDIerrBadType  	-3    	Bad type of event
MIDIerrIndex    	-4    	Wrong field index of access to an event



Midi Change Codes


List of the change codes sended by MidiShare to ApplAlarm.
When an application need to know about context modifications like
opening and closing of applications, opening and closing of midi
ports, changes in connections between applications, it can install an
ApplAlarm (see MidiSetApplAlarm). This ApplAlarm is then called by
MidiShare every time a context modification happens with a 32-bits
code describing the modification. The hi 16-bits part of this code is
the refNum of the application involved in the context modification,
the low 16-bits part describe the type of change as listed below.

Name           	Code    	Comment

MIDIOpenAppl     	1    	A new application is opened
MIDICloseAppl    	2    	An application is closed
MIDIChgName      	3    	The name of an application is changed
MIDIChgConnect   	4    	A connection is changed
MIDIOpenModem    5    	The Modem port is opened
MIDICloseModem   	6    	The Modem Port is closed
MIDIOpenPrinter  	7    	The Printer port is opened
MIDIClosePrinter 	8    	The Printer Port is closed

MIDISyncStart    	550 	Start of synchronization
MIDISyncStop     	551 	End of synchronization
MIDIChangeSync   	552 	The synchronization mode is changed



REFERENCE



MidiAddField


Description
Adds a field at the tail of an event of variable length
(for example a System Exclusive or a Stream) and assigns to it
the value transmitted as a parameter.

Prototype
C Atari    :  void        MidiAddField (e, v);
C Mac ANSI :  pascal void MidiAddField (MidiEvPtr e, long v);
Pascal Mac :  procedure   MidiAddField (e:MidiEvPtr; v:longint);
Gfa Basic  :  procedure   midi_add_field( e%, v%)

Arguments
e :    a MidiEvPtr, it is a pointer to the event to be modified.
v :    a 32-bit integer, it is the value of the field to be added.
    This value is always a long for a purpose of uniformity, but
    it is internally translate to the right size (a byte in this
    case). The value of v is actually between 0 and 127 for a System
    Exclusive and between 0 and 255 for a Stream.


Example 1 (ANSI C)

Creates the System Exclusive message "F0 67 18 05 F7"

MidiEvPtr    e;

e = MidiNewEv (typeSysEx);
MidiAddField (e, 0x67L);
MidiAddField (e, 0x18L);
MidiAddField (e, 0x05L);


Note : the leading F0 byte and the tailing F7 byte are automaticaly
added by MidiShare when the message is transmitted. They must not
be added by the user.


Example 2 (ANSI C)

Creates the Stream message "F8 F0 67 F8 18 05 F7" that mix a
System Exclusive and two MidiClock (F8)

MidiEvPtr    e;
long     i;

e = MidiNewEv(typeStream);
MidiAddField (e, 0xF8L);
MidiAddField (e, 0xF0L);
MidiAddField (e, 0x67L);
MidiAddField (e, 0xF8L);
MidiAddField (e, 0x18L);
MidiAddField (e, 0x05L);
MidiAddField (e, 0xF7L);

Note : Streams are sended without any transformation (no running
status, no check of coherence). They can be used for example to
send a long system exclusive split into several chuncks with a
little delay between. They can also be used as in the example to
mix real time messages in a long system exclusive for maintaining
synchronisation.


Example 3 (ANSI C)

Create a system exclusive message from an array of values:

char         tab[3] = {10, 20, 30};
MidiEvPtr     aSysEx;

MidiEvPtr Array2SysEx( short len, char* vect, short chan, short port )
{
    MidiEvPtr e;

    e = MidiNewEv( typeSysEx );             /* a new, empty sysex   */
    Chan(e) = chan; Port(e) = port;         /* set destination info */
    while (len--) MidiAddField(e, *vect++); /* append fields        */
    return e;
}

aSysEx = Array2SysEx(3, tab, 0, 0);



MidiAddSeq     


Description
Inserts an event in a sequence while maintaining the dates in
time order.

Prototype
C Atari    : void        MidiAddSeq (s, e);
C Mac ANSI : pascal void MidiAddSeq (MidiSeqPtr s, MidiEvPtr e);
Pascal Mac : procedure   MidiAddSeq (s:MidiSeqPtr; e:MidiEvPtr);
Gfa Basic  : procedure   midi_add_seq( s%, e%)

Arguments
s :    a MidiSeqPtr, it is a pointer on the sequence to be modified.
e :    a MidiEvPtr, it is a pointer on the event to be added.


Example (ANSI C)

Creates a sequence of 10 midi clock every 250 ms.

MidiSeqPtr    s;
MidiEvPtr    e;
long    d;

s = MidiNewSeq();
for (d=0; d< 2500; d+=250)
{
    e = MidiNewEv (typeClock);
    Date(e) = d;
    MidiAddSeq (s, e);
}

Note : if you are concerned by speed, you must know that
sequences are single linked lists of time ordered events,
so it takes more time for MidiAddSeq to insert an event in
the middle of a sequence that either at the begining or at
the end.


         
MidiApplySeq


Description
This procedure is an iterator. It allows to apply a procedure to
all the events of a sequence.

Prototype of MidiApplySeq
C Atari    : void        MidiApplySeq (s, MyProc);
C Mac ANSI : pascal void MidiApplySeq (MidiSeqPtr s, ApplyProcPtr p);
Pascal Mac : procedure   MidiApplySeq (s:MidiSeqPtr; p:ApplyProcPtr);
Gfa Basic  : <not implemented>

Arguments of MidiApplySeq
s      : a MidiSeqPtr, it is a pointer to the sequence to be browsed;
MyProc : a ApplyProcPtr is the address of the procedure to apply to
         each event of the sequence.

Prototype of MyProc
C Atari       : void        MyProc (e);
Turbo C Atari : void cdecl  MyProc (MidiEvPtr e);
C Mac ANSI    : pascal void MyProc (MidiEvPtr e);
Pascal Mac    : procedure   MyProc (e:MidiEvPtr);

Argument of MyProc
e : a MidiEvPtr, it is a pointer to the current event in the sequence.


Example (ANSI C)

Transpose a sequence by one octave.

MidiSeqPtr    s;
....

void TransposeOctave (MidiEvPtr e)
{
    if( EvType(e) == typeNote ||
        EvType(e) == typeKeyOn ||
        EvType(e) == typeKeyOff ||
        EvType(e) == typeKeyPress )
        {
            Pitch(e) += 12; /* normally one must check boundaries */
        }
}

MidiApplySeq(s, TransposeOctave);    /* s is a previously created */
                                    /* sequence                  */

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all procedure passed as arguments
of a MidiShare function must be declared as Pascal. In the previous
exemple, TransposeOctave should be declared as :
pascal void TransposeOctave (MidiEvPtr e)



MidiAvailEv      


Description
Gives a pointer to the first event at the head of the reception fifo,
without extracting it. MidiAvailEv can be used for very special
purposes when one wants to test the first event in the reception fifo
of the application, but without processing it.

Prototype
C Atari    : MidiEvPtr MidiAvailEv (refnum) ;
C Mac ANSI : pascal MidiEvPtr MidiAvailEv (short refnum) ;
Pascal Mac : Function  MidiAvailEv (refnum: integer) : MidiEvPtr;
Gfa Basic  : Function  midi_avail_ev(refnum&) : MidiEvPtr

Arguments
refNum : a 16-bit integer, it is the reference number of the
         application.


Result
The result is a MidiEvPtr, a pointer to the first event in the
reception fifo, or NIL if the reception fifo is empty.


Example (ANSI C)

A function that calculate for how long events have been waiting in
the reception fifo.

long CalculateWaitTime (short refNum)
{
    MidiEvPtr    e;

    if (e = MidiAvailEv (refNum))
        return MidiGetTime() - Date(e);
    else
        return 0;
}

Note : as the event is still in the reception fifo, it must not be
destroyed neither sended. It can just be tested or duplicated.


           
MidiCall       


Description
Defines a time delayed procedure call. When the calling date falls in,
the call is automatically realized by MidiShare under interruptions.
MidiCall is presented here for historical reasons, but MidiTask is a
better choice.

Prototype of MidiCall
C Atari    : void        MidiCall (MyProc, date, refNum, a1, a2, a3);
C Mac ANSI : pascal void MidiCall (TaskPtr MyProc, long date,
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Procedure   MidiCall (MyProc:TaskPtr; date:longint;
                                   refNum:integer; a1,a2,a3: longint);
Gfa Basic  : <not implemented>

Arguments of MidiCall
MyProc   : a TaskPtr, it is the address of the procedure to be called.
date     : a 32-bit integer, it is the date at which this call is
           scheduled.
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as
           arguments of MyProc

Prototype of MyProc
C Atari       : void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari : void cdecl  MyProc (long date, short refNum,
                                 long a1, long a2, long a3);
C Mac ANSI    : pascal void MyProc (long date, short refNum,
                                 long a1, long a2, long a3);
Pascal Mac    : procedure   MyProc (date:longint; refNum:integer;
                                 a1,a2,a3: longint);

Argument of MyProc
date     : a 32-bit integer, it is the date of the call .
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


Example (ANSI C )

Send periodicaly, every 10 ms, a MidiClock during 30 seconds.

void MyClock(long date, short refNum, long delay, long limit,long a3)
{
    if (date < limit)
    {
        MidiSendIm (refNum, MidiNewEv(typeClock));
        MidiCall (MyClock, date+delay, refNum, delay, limit, a3);
    }
}
...........
long d;
...........
d = MidiGetTime();
MyClock (d, myRefNum, 10L, d+30000L, 0L); /* Start now the clock */
                                         /* for 30s             */

Note : This call being done under interruptions, a few precautions
should be taken, such as not invoking non-reentrant routines of
the Operating System (such as the Memory Manager on the Macintosh
for example). On the contrary, most of the MidiShare functions are
reentrant, they can be used safely under interrupts.

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all procedure passed as arguments
of a MidiShare function should be declared as Pascal.
In the previous exemple, MyClock should be declared as :
pascal void MyClock(long date, short refNum, long delay,
                                     long limit, long a3);


               
MidiClearSeq


Description
Frees the content of a sequence. MidiClearSeq de-allocates all
the events of the given sequence. By consequence this sequence
becomes empty.

Prototype
C Atari    : void        MidiClearSeq (s);
C Mac ANSI : pascal void MidiClearSeq (MidiSeqPtr s);
Pascal Mac : procedure   MidiClearSeq (s:MidiSeqPtr);
Gfa Basic  : procedure   midi_clear_seq(s%)

Arguments
s : a MidiSeqPtr, it is a pointer on a sequence whose events are
    to be freed.


Example (ANSI C)

Suppress all but the first event of a sequence.

void ClearAllButFirst (MidiSeqPtr s)
{
    MidiEvPtr e;

    if (s && First(s))             /* Check a non empty sequence */
    {
        e = MidiCopyEv(First(s));  /* make a safe copy of the    */
                                   /* first event                */
        MidiClearSeq(s);           /* clear the content of the   */
                                   /* sequence                   */
        MidiAddSeq(s, e);          /* add the event to the empty */
                                   /* sequence                   */
    }
}


Note : a sequence consist of a header of 4 pointers. The first one
points to the first event of the sequence. The second one points
to the last event. The other two pointers are reserved for future
extensions and must be NIL. In an empty sequence, the pointers to
the first and last events are NIL.



MidiClose   


Description
Closing of a MidiShare application. Every opening of MidiShare with
MidiOpen must be counter-balanced by a call to MidiClose, so that
MidiShare keeps the exact account of active applications and released
the corresponding internal data structures. All the MidiShare
applications owning a "context alarm" will be informed of
this closing.

Prototype
C Atari    : void        MidiClose (refNum);
C Mac ANSI : pascal void MidiClose (short refNum);
Pascal Mac : procedure   MidiClose (refNum:integer);
Gfa Basic  : procedure   midi_close(refNum&)

Arguments
refNum : a 16-bit integer, it is the reference number of the
         application, given by the corresponding MidiOpen.


Example (ANSI C)

A DoNothing MidiShare application.
#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
    if ( ! MidiShare() )     exit(1);    /* Check MidiShare loaded */
    myRefNum = MidiOpen("Sample");       /* Ask for a ref. number  */
    if ( myRefNum < 1 )     exit(1);     /* Check MidiOpen success */
    printf( "refNum : %i \n", myRefNum); /* Print the ref. number  */
    MidiClose(myRefNum);                 /* And close              */
}

Note : MidiClose take care of deleting all the connections with the
concerned application. Therefore if an application sends some Midi
events and without delay, does a MidiClose, these sended events will
probably not be actually transmitted. They just go back to the
MidiShare Memory Manager.

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all strings passed as arguments
of a MidiShare function must be Pascal strings. In the previous
exemple, one must write :
myRefNum = MidiOpen("\pSample");


                 
MidiConnect  


Description
Connects or disconnects two applications. The MidiConnect procedure
allows to switch on or off a connection between a source application
and a destination application. There is no restrictions to the
establishing of connections, an application can be source or
destination as many times as you wish. Loops are permitted.

Prototype
C Atari   : void        MidiConnect (src, dest, state);
C Mac ANSI: pascal void MidiConnect (short src, short dest,
                                              boolean state);
Pascal Mac: Procedure   MidiConnect (src, dest:integer; state:boolean);
Gfa Basic : Procedure   midi_connect(src&,dest&,state!)

Arguments
src   : a 16-bit integer, it is the reference number of the source
        application.
dest  : a 16-bit integer, it is the reference number of the
        destination application.
state : a boolean, it indicates if a connection must be switched on
        (True) or off (False).


Example (ANSI C)

Open a MidiShare application and connect it to the physical Midi
inputs and outputs.

#include MidiShare.h
#define PHYSMIDI_IO 0    /* The MidiShare physical Midi I/O ports*/

Main()
{
    short    myRefNum;

    myRefNum = MidiOpen("MidiSample");

    MidiConnect(PHYSMIDI_IO, myRefNum, TRUE); /* to receive events */
    MidiConnect(myRefNum, PHYSMIDI_IO, TRUE); /* to transmit events*/

    /* ....... */

    MidiClose(myRefNum);
}

Note : the physical Midi inputs and outputs are represented by the
pseudo application called "MidiShare" with a reference number of 0
(zero). This pseudo application is automaticaly created when
MidiShare wakes up at the very first MidiOpen.


           
MidiCopyEv


Description
Duplicates an event. MidiCopyEv takes into account the structure of
the event. It can be used to copy every type of events, from simple
notes to big system exclusives.

Prototype
C Atari    : MidiEvPtr        MidiCopyEv (e);
C Mac ANSI : pascal MidiEvPtr MidiCopyEv (MidiEvPtr e);
Pascal Mac : Function         MidiCopyEv (e: MidiEvPtr): MidiEvPtr;
Gfa Basic  : Function         midi_copy_ev(e%) : MidiEvPtr

Arguments
e :     a MidiEvPtr, it is a pointer to the event to be copied.

Result
The result is a MidiEvPtr, a pointer to the copy if the operation
was sucessfull. The result is NIL if MidiShare was not able to
allocate enough memory space for the copy.


Example (ANSI C)

Send from now, 10 times an identical note of pitch 60 every 250 ms.

MidiEvPtr    e;
short        myRefNum;
long         d;
short        i;
........

e = MidiNewEv (typeNote);    /* create template note      */
Pitch(e)= 60;                /* fill up its parameters    */
Vel(e)  = 80;
Dur(e)  = 250;
Chan(e) = 0;
Port(e) = 0;

for (d=MidiGetTime(), i=0; i<10; i++, d+=250) /* send the 10 copies*/
    MidiSendAt (myRefNum, MidiCopyEv(e), d);  /*   of the template */

MidiFreeEv(e);                            /* and free the template */


Note : it is very important to note that, once an event is sended, it
must never be used any more by the application. Consequently, if one
need to send several times the same midi message, one must send
different copies.



MidiCountAppls  


Description
Gives the number of Midi applications active.

Prototype
C Atari    : short        MidiCountAppls();
C Mac ANSI : pascal short MidiCountAppls();
Pascal Mac : Function     MidiCountAppls : integer;
Gfa Basic  : Function     midi_count_appls : integer

Result
The result is a 16-bit integer, the number of currently opened Midi
applications.


Example (ANSI C)

Print the name of all the actives MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;

    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}

Note for Mac users : MidiShare was originaly developed for Pascal
on the Macintosh. Consequently, in C, the result of MidiGetName is
a Pascal string that must be converted to a C string before being
printed.


       
MidiCountDTasks 


Description
Returns the number of time delayed tasks waiting in the list of the
application. Delayed tasks are function calls that where scheduled
with MidiDTask and that are now ready to be executed in the
DTasksFifo of the application.

Prototype
C Atari    : long        MidiCountDTasks (refNum);
C Mac ANSI : pascal long MidiCountDTasks (short refNum);
Pascal Mac : Function    MidiCountDTasks (refNum: integer): longint;
Gfa Basic  : <not implemented>

Arguments
refNum : a 16-bit integer, the reference number of the application.

Result
The result is a 32-bit integer, the number of waiting DTasks.


Example (ANSI C)

Execute the waiting DTasks of a MidiShare application.

void ExecuteAllDTasks(short refNum)
{
    long    n;

    for (n=MidiCountDTasks(refNum), n>0; n--)
    {
        MidiExec1DTask(refNum);
    }
}

Note : This is what a typical application must do, generaly in its
main event loop, to actually execute previously scheduled
MidiDTasks. Since these MidiDTasks are executed in the main event
loop, they can do Operating System call without trouble. In return,
as MidiDTasks are not executed under interrupts, they are not as
accurate in time as MidiTasks.


   
MidiCountEvs


Description
Gives the number of events waiting on the reception fifo of the
application.

Prototype
C Atari    : long        MidiCountEvs (refnum);
C Mac ANSI : pascal long MidiCountEvs (short refnum);
Pascal Mac : Function    MidiCountEvs (refnum: integer) : longint;
Gfa Basic  : Function    midi_count_evs(refnum&) : longint

Arguments
refNum : a 16-bit integer, the reference number of the application.

Result
The result is a 32-bit integer, the number of waiting events in the
reception fifo.


Example (ANSI C)

A receive alarm that processes all the received events by adding to
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n )
    {
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);  /* Activate the receive */
                                        /* alarm                */


Note : such a procedure can be called repeatedly in the main event
loop of the application, but for really accurate time control, it
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all procedure passed as arguments
of a MidiShare function must be declared as Pascal. In the previous
exemple, OneSecDelay must be declared as :
pascal void OneSecDelay (short refNum)



MidiCountFields


Description
Gives the number of fields of an event.

Prototype
C Atari    : long        MidiCountFields (e);
C Mac ANSI : pascal long MidiCountFields (MidiEvPtr e);
Pascal Mac : Function     MidiCountFields (e: MidiEvPtr): longint;
Gfa Basic  : Function     midi_count_fields(e%) : longint

Arguments
e :     a MidiEvPtr, a pointer to the concerned event.

Result
The result is a 32-bit integer, the number of fields of the event.


Example (ANSI C)

An universal method for printing of a MidiShare event.

void PrintEv(MidiEvPtr e)
{
    long i, n;

    n = MidiCountFields(e);
    printf( "Event %x content :\n", e );
    printf( " link : %x\n", Link(e) );
    printf( " date : %i\n", Date(e) );
    printf( " type : %i\n", EvType(e) );
    printf( "  ref : %i\n", RefNum(e) );
    printf( " port : %i\n", Port(e) );
    printf( " chan : %i\n", Chan(e) );
    printf( " %i fields : ( ", n );
    for(i=0; i<n; ++i) printf("%i ",MidiGetField(e,i) );
    printf( ")\n" );
}

Note : MidiShare events carry two kind of information :
common information, like date, type, channel, port ...,
and specific information that depend of the type of event.
Fields allow a uniform way to access these specific information.
Some events have fixed number of fields (for exemple notes have
three fields : pitch (8-bit), velocity (8-bit) and duration (16-bit)).
Some other, like system exclusive have a variable number of fields.


        
MidiDTask 


Description
In the same way as MidiTask, MidiDTask allows to realize a time
delayed procedure call ; but on the reverse to MidiTask, the call is
not achieved under interruption as soon as falling time is due.
The address of the routine to be executed and the corresponding
arguments will be stored into a special list. The application will
be allowed to process these on-wait tasks, one by one, thanks to
MidiExec1DTask.

Prototype of MidiDTask
C Atari    : MidiEvPtr MidiDTask (MyProc, date, refNum,
                                                      a1, a2, a3);
C Mac ANSI : pascal MidiEvPtr MidiDTask (ProcPtr MyProc, long date,
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Function MidiDTask (MyProc:ProcPtr; date:longint;
                    refNum:integer; a1,a2,a3: longint):MidiEvPtr;
Gfa Basic  : <not implemented>

Arguments of MidiDTask
MyProc   : is the address of the procedure to be called.
date     : a 32-bit integer, it is the date at which this call
           is scheduled.
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as
           arguments to MyProc

Result of MidiDTask
The result, a MidiEvPtr, is a pointer to a typeDProcess MidiShare
event. The result is NIL if MidiShare runs out of memory.

Prototype of MyProc
C Atari       :    void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari :    void cdecl  MyProc (long date, short refNum,
                                    long a1, long a2, long a3);
C Mac ANSI    :    pascal void MyProc (long date, short refNum,
                                    long a1, long a2, long a3);
Pascal Mac    :    procedure   MyProc (date:longint; refNum:integer;
                                    a1,a2,a3: longint);

Argument of MyProc
date     : a 32-bit integer, it is the date of the call .
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


Example (ANSI C)

Schedule Action() procedure call 1000 ms ahead.

MidiEvPtr    myDTask;

MyDTask = MidiDTask(Action,MidiGetTime()+1000,myRefNum, a1, a2, a3);

Note : The result, in myDTask, can be used to test the success of
MidiDTask. It can also be used by MidiForgetTask to try to "forget"
a scheduled task before it happens.


                
MidiExec1DTask


Description
Processes the first time delayed task on wait in the application list.
The time delayed tasks scheduled by MidiDTask are not processed as
soon as time falls in, but stored into a special list proper to each
application, so they can be processed out of interruption.

Prototype
C Atari    : void        MidiExec1DTask (refnum);
C Mac ANSI : pascal void MidiExec1DTask (short refnum);
Pascal Mac : procedure   MidiExec1DTask (refnum: integer);
Gfa Basic  : <not implemented>

Arguments
refNum     : a 16-bit integer, it is the reference number of the
          application.


Example (ANSI C)

Execute the waiting DTasks of a MidiShare application.

void ExecuteAllDTasks(short refNum)
{
    long    n;

    for (n=MidiCountDTasks(refNum), n>0; n--)
    {
        MidiExec1DTask(refNum);
    }
}

Note : This is what a typical application must do, generaly in its
main event loop, to actually execute previously scheduled MidiDTasks.
Since these MidiDTasks are executed in the main event loop, they can
do Operating System Call without trouble. In return, as MidiDTasks
are not executed under interrupts, they are not as accurate in time
as MidiTasks.



MidiExt2IntTime 


Description
Convert an external time in millisecond to an internaltime.
The convertion is made by substractiong the current offset between
internal and external time.

Prototype
C Atari    :    long         MidiExt2IntTime(time);
C Mac ANSI :    pascal long  MidiExt2IntTime(long time);
Pascal Mac :    Function     MidiExt2IntTime(time : longint): longint;
Gfa Basic  :    Function     midi_ext_2_int_time(time%) : longint

Arguments
time : a 32-bits time in milliseconds

Result
the corresponding internal time, a 32-bits value in milliseconds.


Note :
When MidiShare is locked we have the following equivalence :
    MidiExt2IntTime( MidiGetExtTime() ) == MidiGetTime()
We have also :
    TSyncInfo myInfo;
    MidiGetSyncInfo(&myInfo);
    MidiExt2IntTime(x) == x - myInfo.syncOffset


       
MidiFlushDTasks  


Description
Flushes all the waiting DTasks in the application DTask list.

Prototype
C Atari    : void        MidiFlushDTasks (refnum);
C Mac ANSI : pascal void MidiFlushDTasks (short refnum);
Pascal Mac : procedure   MidiFlushDTasks (refnum: integer);
Gfa Basic  : <not imlemented>

Arguments
refNum : a 16-bit integer, it is the reference number of the
         application.


Example (ANSI C)

Flushes all the waiting DTasks in the application DTask list.

short    myRefNum;

.....

MidiFlushDTasks (myRefNum);


   
MidiFlushEvs


Description
Flushes all the waiting events in the reception fifo of the
application.

Prototype
C Atari    : void        MidiFlushEvs( refNum );
C Mac ANSI : pascal void MidiFlushEvs( short refNum );
Pascal Mac : procedure   MidiFlushEvs( refNum : integer );
Gfa Basic  :
HyperCard  :

Arguments
refNum     : a 16-bit integer, it is the reference number of the
          application.


Example (ANSI C)

Flushes all the waiting events in the application reception fifo.

short    myRefNum;

.....

MidiFlushEvs (myRefNum);



MidiForgetTask  


Description
Tries to "forget" a previously scheduled Task or DTasks. This a very
powerful, but dangerous function. One must be sure that the task
is not yet executed before calling MidiForgetTask.

Prototype
C Atari    : void        MidiForgetTask (v);
C Mac ANSI : pascal void MidiForgetTask (MidiEvPtr *v);
Pascal Mac : procedure   MidiForgetTask (var v: MidiEvPtr);
Gfa Basic  : <not implemented>

Arguments
v : is the address of a variable pointing to a previously
    scheduled Task or DTask but not yet executed. The variable
    may also contain NIL. In this case MidiForgetTask does nothing.

Side effect
The variable, wich address is given in parameter, is set to NIL by
MidiForgetTask.


Example 1 (ANSI C)

Create an infinit periodic clock (every 250ms) and stop it with
MidiForgetTask.

MidiEvPtr   theClock;

void InfClock (long date, short refNum, long delay, long a2, long a3)
{
    MidiSendIm (refNum, MidiNewEv(typeClock));
    theClock = MidiTask (InfClock, date+delay, refNum, delay, a2, a3);
}

InfClock(MidiGetTime(), myRefNum, 250L, 0L, 0L); /* Start the clock */
.........                                        /* Wait some time  */
MidiForgetTask(&theClock);                       /* And forget it   */


Example 2 (ANSI C)

In the previous example, theClock always point to a valid task because
InfClock never stop by itself. If the task may decide to stop itself,
it must set the pointer to NIL in order to avoid to forget an invalid
task.

MidiEvPtr    theClock;

void CountClock (long date, short refNum, long delay, long count, long a3)
{
   if( count > 0)
   {
      MidiSendIm (refNum, MidiNewEv(typeClock));
      theClock = MidiTask (CountClock, date+delay, refNum, delay, count-1, a3);
   } else {
      theClock = nil;     /* here the task decide to stop itself */
                          /* so set the pointer to nil           */
   }

InfClock(MidiGetTime(), myRefNum, 250L, 100L, 0L); /* Start the clock  */
.........                                          /* Wait some time   */
MidiForgetTask(&theClock);                         /* And forget it    */

If MidiForgetTask happens before the end of the 100 clocks, theClock point
to a valid task and MidiForgetTask(&theClock) is safe. If MidiForgetTask
happens after the end of the 100 clocks, theClock contains NIL and
MidiForgetTask(&theClock) is safe and will do nothing.


       
MidiFreeCell  


Description
Frees a cell allocated by MidiNewCell function. This is the lowest
level for accessing the MidiShare Memory Manager. One must be shure
to use MidiFreeCell on an individual cell allocated with MidiNewCell
and not on complet MidiShare events. Not doing so may result on
losting cells.

Prototype
C Atari    : void        MidiFreeCell (c);
C Mac ANSI : pascal void MidiFreeCell (MidiEvPtr c);
Pascal Mac : procedure   MidiFreeCell (c: MidiEvPtr);
Gfa Basic  : procedure   midi_free_cell(c%)

Arguments
c :     a MidiEvPtr, a pointer to a basic cell of 16 bytes.


Example (ANSI C)

Free a cell previously allocated.

MidiEvPtr    aCell;

aCell = MidiNewCell();

....

MidiFreeCell( aCell );

Note : Cells allocated with MidiNewCell must be freed with
MidiFreeCell and not with MidiFreeEv.


            
MidiFreeEv


Description
Frees a MidiShare event allocated with MidiNewEv. MidiFreeEv takes
into account the event structure by checking the event type. For
this reason, MidiFreeEv must not be used on cell allocated with
MidiNewCell.

Prototype
C Atari    : void        MidiFreeEv (e);
C Mac ANSI : pascal void MidiFreeEv (MidiEvPtr e);
Pascal Mac : procedure   MidiFreeEv (e: MidiEvPtr);
Gfa Basic  : procedure   midi_free_ev(e%)

Arguments
e :     a MidiEvPtr, it is a pointer to a MidiShare event.


Example (ANSI C)


A receive alarm that delete all the received events.

short    myRefNum;
.....

void DeleteAll( short refNum )
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n )
    {
        e = MidiGetEv( refNum );    /* Get an event from the fifo */
        MidiFreeEv( e );            /* Then free it               */
    }
}
......

MidiSetRcvAlarm( myRefNum, DeleteAll ); /* Activate receive alarm */


Note : Obviously it is more simple and fast to use MidiFlushEvs to
achieve the same result.

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all procedure passed as arguments
of a MidiShare function must be declared as Pascal. In the previous
exemple, DeleteAll must be declared as :
pascal void DeleteAll( short refNum )



MidiFreeSeq   


Description
Frees a sequence and its content. MidiFreeSeq first de-allocates all
the events of the given sequence and then the sequence header itself.

Prototype
C Atari    : void        MidiFreeSeq (s);
C Mac ANSI : pascal void MidiFreeSeq (MidiSeqPtr s);
Pascal Mac : procedure   MidiFreeSeq (s:MidiSeqPtr);
Gfa Basic  : procedure   midi_free_seq(s%)

Arguments
s :    a MidiSeqPtr, it is a pointer on a sequence to be freed.


Example (ANSI C)

Frees a previously allocated sequence s.

MidiSeqPtr    s;

s = MidiNewSeq();
....
MidiFreeSeq(s);

Note : Once freed, s is no more a valid pointer.


          
MidiFreeSpace   


Description
Gives the available space. MidiFreeSpace allows to know at any time
the number of cells remaining available from the MidiShare memory
manager.

Prototype
C Atari    : long        MidiFreeSpace();
C Mac ANSI : pascal long MidiFreeSpace(void);
Pascal Mac : Function    MidiFreeSpace : longint;
Gfa Basic  : Function    midi_free_space : longint

Arguments
none

Result
The result is a 32-bit integer, the number of available free
cells in the MidiShare memory manager.


Example (ANSI C)

Print informations about MidiShare memory space.

void PrintMemInfo(void)
{
 printf("MidiShare memory :\n");
 printf("free space  : %i cells\n", MidiFreeSpace());
 printf("used space  : %i cells\n", MidiTotalSpace()-MidiFreeSpace());
 printf("total space : %i cells\n", MidiTotalSpace());
}

Note : MidiFreeSpace inhibits all interrupts during its execution.
If the remaining space is very large MidiFreeSpace can take a long
time to execute and may cause overrun errors with fast incoming
Midi data.


      
MidiGetApplAlarm


Description
Gives the context alarm of an application. MidiGetAlarm allows to
know the address of the context alarm procedure associated to the
application. This alarm is automatically called by MidiShare to
inform the application of all the changes happened into the active
Midi applications (name or connection changes, closing, opening, etc.)

Prototype of MidiGetApplAlarm
C Atari    : ApplAlarmPtr        MidiGetApplAlarm(refNum);
C Mac ANSI : pascal ApplAlarmPtr MidiGetApplAlarm(short refNum);
Pascal Mac : Function MidiGetApplAlarm(refNum: integer): ApplAlarmPtr;
Gfa Basic  : <not implemented>

Arguments of MidiGetApplAlarm
refNum : a 16-bit integer, it is the reference number of the
         application.

Result
the result, a ApplAlarmPtr, is the address of the alarm routine or NIL
if no such routine where installed.

Prototype of an ApplAlarm routine
C Atari    : void        MyApplAlarm (refNum, code);
C Mac ANSI : pascal void MyApplAlarm (short refNum, long code);
Pascal Mac : procedure   MyApplAlarm (refNum:integer;code:longint);

Argument of an ApplAlarm routine
refNum : a 16-bit integer, it is the reference number of the
          application.
code   : a 32-bit integer, the context modification code.


Example (ANSI C)

Disable temporarily the application context alarm.

ApplAlarmPtr p;
.....
p = MidiGetApplAlarm( myRefNum );
MidiSetApplAlarm( NIL );    /* Disable application context alarm  */
.....
MidiSetApplAlarm( p );      /* Restaure application context alarm */



MidiGetEv       


Description
Extracts the event on top of the reception fifo. The received events,
stored automaticaly by MidiShare in the application reception fifo,
can be picked up by successive calls to MidiGetEv function.

Prototype
C Atari    : MidiEvPtr        MidiGetEv (refNum) ;
C Mac ANSI : pascal MidiEvPtr MidiGetEv (short refNum) ;
Pascal Mac : Function    MidiGetEv (refNum: integer) : MidiEvPtr;
Gfa Basic  : Function    midi_get_ev(refNum&) : MidiEvPtr

Arguments
refNum : a 16-bit integer, it is the reference number of the
         application.


Result
a MidiEvPtr, a pointer to the first event in the reception Fifo,
or NIL if the fifo is empty. The event is extracted form the
reception fifo.


Example (ANSI C)

A receive alarm that processes all the received events by adding to
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n )
    {
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Activate the receive alarm*/


Note : such a procedure can be called repeatedly in the main event
loop of the application, but for really accurate time control, it
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal
on the Macintosh. Consequently, in C, all procedure passed as
arguments of a MidiShare function must be declared as Pascal. In
the previous exemple, OneSecDelay must be declared as :

pascal void OneSecDelay (short refNum)



MidiGetExtTime  


Description
Return the current external time, the position of the tape converted
in milliseconds.

Prototype
C Atari    : long         MidiGetExtTime();
C Mac ANSI : pascal long  MidiGetExtTime (void);
Pascal Mac : Function     MidiGetExtTime : longint;
Gfa Basic  : Function midi_get_ext_time(void) : longint

Arguments
none


Example (ANSI C)

Gives the SMPTE current location of the tape.

  TSyncInfo      myInfo;
  TSmpteLocation myLoc;

  MidiGetSyncInfo(&myInfo);
  MidiTime2Smpte( MidiGetExtTime(), myInfo.syncFormat, &myLoc);


Note: when the tape is stopped, MidiGetExtTime returns the stop
position of the tape converted in milliseconds.



MidiGetField
 

Description
Return the i index field value of an event. Field index start from 0.
Depending of the event type and field nature, the field format can
be 8, 16 or 32-bit. MidiGetField deals with all the format conversion
and the result is always a 32-bit integer.

Prototype
C Atari    : long           MidiGetField (e, f);
C Mac ANSI : pascal long    MidiGetField (MidiEvPtr e, long f);
Pascal Mac : Function MidiGetField(e: MidiEvPtr; f: longint):longint;
Gfa Basic  : Function midi_get_field(e%,f%)

Arguments
e :    a MidiEvPtr, it is a pointer on the event to be acces.
f :    a 32-bit integer, it is the field number to be read
    (numbered from 0).

Result
The result is a 32-bit integer, the value of the field. Fields are
considered as unsigned.


Example (ANSI C)

An universal method for printing of a MidiShare event.

void PrintEv(MidiEvPtr e)
{
    long i, n;

    n = MidiCountFields(e);
    printf( "Event %x content :\n", e );
    printf( " link : %x\n", Link(e) );
    printf( " date : %i\n", Date(e) );
    printf( " type : %i\n", EvType(e) );
    printf( "  ref : %i\n", RefNum(e) );
    printf( " port : %i\n", Port(e) );
    printf( " chan : %i\n", Chan(e) );
    printf( " %i fields : ( ", n );
    for(i=0; i<n; ++i) printf("%ld ",MidiGetField(e,i) );
    printf( ")\n" );
}

Note : MidiShare events carry two kind of information :
common information, like date, type, channel, port ..., and
specific information that depend of the type of event. Fields
allow a uniform way to acces these specific information. Some
events have fixed number of fields (for example notes have three
Fields : pitch (8-bit), velocity (8-bit) and duration (16-bit)).
Some other, like system exclusive have a variable number of fields.



MidiGetFilter    


Description
Gives the associated filter of an application. Each application can
select the events to be received by using a filter. The filtering
processus is local to the application and has no influence on the
events received by other applications.

Prototype
C Atari    : FilterPtr        MidiGetFilter (refNum);
C Mac ANSI : pascal FilterPtr MidiGetFilter (short refNum);
Pascal Mac : Function MidiGetFilter (refNum: integer): FilterPtr;
Gfa Basic  : Function midi_get_filter(refNum&) : FilterPtr

Arguments
refNum :     a 16-bit integer, the reference number of the application

Result
the result is a FilterPtr, a pointer to the filter associated to the
application, or NIL if there is no such filter (in this case the
application accepts any events)


Example (ANSI C)
                    << to be supplied >>



MidiGetIndAppl  


Description
Gives the reference of number of an application from is order number.
The MidiGetIndAppl function allows to know the reference number of
any application by giving its order number (a number between 1 and
MidiCountAppls() ).

Prototype
C Atari    : short        MidiGetIndAppl (index);
C Mac ANSI : pascal short MidiGetIndAppl (short index);
Pascal Mac : Function MidiGetIndAppl (index: integer) : integer;
Gfa Basic  : Function midi_get_ind_appl(index&) : integer

Arguments
index :     a 16-bit integer, it is the index number of an application
between 1 and MidiCountAppls().

Result
The result is an application reference number or MIDIerrIndex if the
index is out of range.


Example (ANSI C)

Print the name of all the actives MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;

    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, the result of MidiGetName is a
Pascal string that must be converted to a C string before being
printed.



MidiGetInfo


Description
Gives the content of a 32-bit field an application can use for
any purpose. This field remains accessible by MidiGetInfo during
alarms and interrupts. It can be used as a global context if
necessary (for example for desk accessories on the Macintosh)

Prototype
C Atari    : Ptr          MidiGetInfo( short refNum );
C Mac ANSI : pascal void *MidiGetInfo( short refNum );
Pascal Mac : Function     MidiGetInfo( refNum: integer ) : Ptr;
Gfa Basic  : Function     mdi_get_info(refNum&) : Ptr

Arguments
refNum : a 16-bit integer, the reference number of the application

Result : a 32 bits integer : the last value set by MidiSetInfo.


Example (ANSI C)
                    << to be supplied >>



MidiGetName


Description
Gives the name of an application. Knowing an application reference
number, it is possible to find its name using the MidiGetName
function. On the reverse, it is also possible to find the reference
number of an application via its name using the MidiGetNamedAppl
function.

Prototype
C Atari    : MidiName        MidiGetName(refNum);
C Mac ANSI : pascal MidiName MidiGetName(short refNum);
Pascal Mac : Function MidiGetName (refNum: integer) : MidiName;
Gfa Basic  : Function midi_get_name(efNum&) : MidiName

Arguments
refNum : a 16-bit integer, the reference number of the application

Result
The result is pointer on a character string representing the
application name.


Example (ANSI C)

Print the name of all the active MidiShare applications

void PrintApplNames(void)
{
    short     ref;
    short     i;

    printf( "List of MidiShare applications :\n" );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        ref = MidiGetIndAppl(i);
        printf("%i : %s \n", ref, MidiGetName( ref ) );
    }
}

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, the result of MidiGetName is a
Pascal string that must be converted to a C string before being
printed.



MidiGetNamedAppl  


Description
Gives the reference number of an application. Knowing an application
name, it is possible to find its reference number using the
MidiGetNamedAppl function. On the reverse, it is also possible to
find the name of an application via its reference number using the
MidiGetName function.

Prototype
C Atari    : short        MidiGetNamedAppl (MidiName name);
C Mac ANSI : pascal short MidiGetNamedAppl (MidiName name);
Pascal Mac : Function MidiGetNamedAppl (name: MidiName) : integer;
Gfa Basic  : Function midi_get_named_appl(name$) : integer

Arguments
name :     the application name.

Result
The result is the reference number of the application.


Example (ANSI C)

Find the reference number of the "MidiShare" pseudo-application.

short    r;

r = MidiGetNamedAppl("MidiShare");/* MidiShare reference is always 0*/


Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all stings passed as arguments of
a MidiShare function must be Pascal strings. In the previous example,
one must write :
MidiGetNamedAppl("\pMidiShare")



MidiGetPortState


Description
Gives the Midi port state. The switching on or off of Midi ports is
controlled by the MidiSetPortState and MidiGetPortState routines.
These must be used with care since they affect all the applications.

Prototype
C Atari    : Boolean        MidiGetPortState(port);
C Mac ANSI : pascal Boolean MidiGetPortState(short port);
Pascal Mac : Function MidiGetPortState(port: integer): boolean;
Gfa Basic  : Function midi_get_port_state(port&) : boolean

Arguments
port :     a port number from 0 to 255.

Result
The result is true if the port is open or false if the port is closed.


Example (ANSI C)

Print the state of all the Midi ports.

void PrintPortsState(void)
{
    short i;

    printf( "Midi ports state :\n");
    for( i = 0; i < 256; ++i )
    {
        if ( MidiGetPortState( i ) )
            printf(" %i is open \n", i );
        else
            printf(" %i is closed \n", i );
    }
}

Note : On the Atari, there is just one Midi port (port 0), and on
the Macintosh there are just two ports (port modem: 0,
port printer: 1). But the future Lan version of MidiShare will allow
up to 256 ports to be used. Therefore, applications must consider
that 256 ports are available.



MidiGetRcvAlarm  


Description
Gives the address of reception alarm of an application.The reception
alarm warns of the presence of new events in the reception fifo.
This alarm is always called under interruption. Therefore, it must
not make use, either directly or indirectly, the Macintosh Memory
Manager. On the reverse, it can have a free access to all the
MidiShare functions (exept MidiOpen and MidiClose), in particular
event management. It can also use global variables of the application,
because, before the call, MidiShare restaures the global context
register of the application.

Prototype
C Atari    : RcvAlarmPtr        MidiGetRcvAlarm(refNum);
C Mac ANSI : pascal RcvAlarmPtr MidiGetRcvAlarm(short refNum);
Pascal Mac : function MidiGetRcvAlarm(refNum: integer):RcvAlarmPtr;
Gfa Basic  : <not implemented>

Arguments
refNum : a 16-bit integer, the reference number of the application

Result
The result, a RcvAlarmPtr, it is the address of the receive alarm
routine or NIL if no such routine where installed.


Prototype of a RcvAlarm routine
C Atari    : void        MyRcvAlarm (refNum);
C Mac ANSI : pascal void MyRcvAlarm (short refNum);
Pascal Mac : procedure   MyRcvAlarm (refNum:integer);


Argument of a RcvAlarm routine
refNum     : a 16-bit integer, it is the reference number of the
          application.


Example (ANSI C)

Temporarily disable the application receive alarm.

RcvAlarmPtr p;
.....
p = MidiGetRcvAlarm( myRefNum );
MidiSetRcvAlarm( NIL );      /* Disable application receive alarm  */
.....
MidiSetRcvAlarm( p );        /* Restaure application receive alarm */



MidiGetSyncInfo   


Description
Fills a TSyncInfo record with informations about the current state of
the MTC synchronisation.

Prototype
C Atari    : void        MidiGetSyncInfo (p);
C Mac ANSI : pascal void MidiGetSyncInfo (SyncInfoPtr p);
Pascal Mac : procedure   MidiGetSyncInfo (p: SyncInfoPtr);
Gfa Basic  : procedure   midi_get_sync_info(p$)

Arguments
p: a SyncInfoPtr, a pointer to a TSyncInfo record

note for Gfa users : p$ is a string containing at least 34 characters.

description of a TSyncInfo record :

typedef struct TSyncInfo
{
  // the current MidiShare date (in milliseconds)
     long time;
  // the current reentrancy count of the interrupt handler
     long reenter;
  // the current synchronisation mode as defined by MidiSetSyncMode
     unsigned short syncMode;
  // the current synchronisation state (0 : unlocked 1 : locked)
     Byte syncLocked;
  // the current synchronisation port
     Byte syncPort;
  // the date MidiShare started beeing locked to external sync(in ms)
     long syncStart;
  // the date MidiShare stopped being locked to external sync (in ms)
     long syncStop;
  // the current offset (MidiGetExtTime() - MidiGetTime(), in ms)
     long syncOffset;
  // the current value for the timer (implementation dependent)
     long syncSpeed;
  // current count of breaks (transition from state locked to unlocked)
     long syncBreaks;
  // current synchronisation format (0:24f/s,1:25f/s,2:30DFf/s,3:30f/s)
     short syncFormat;
} TSyncInfo;


Note 1

syncMode is an unsigned 16-bits word of struture : xa000000pppppppp.
x (bit 15) is used to choose between internal synchronisation (x=0)
   and external synchronisation (x=1)
a (bit 14) is used to choose between synchronisation on port p (a=0)
   and synchronisation on any port (a=1)
bit 13:8 are reserved for future use and must be set to 0.
p (bit 0:7) is the synchronisation port to be used when x=1 and a=0.
When a=1 the port number is ignored, the first port with incoming MTC
is used.


Note 2

While MidiShare is locked (syncLocked == 1) syncOffset is constant and
we have the following relationships :
    MidiGetExtTime() == MidiGetTime() + syncOffset
    MidiInt2ExtTime(x) == x + syncOffset
    MidiExt2IntTime(x) == x - syncOffset


Example (ANSI C)
Gives the SMPTE start location of the tape.

TSyncInfo       myInfo;
TSmpteLocation myLoc;
MidiGetSyncInfo(&myInfo);
MidiTime2Smpte( MidiInt2ExtTime(myInfo.syncStart), myInfo.syncFormat,
                &myLoc);



MidiGetTime


Description
Return in milliseconds the time past since the starting up of
MidiShare.

Prototype
C Atari    : long        MidiGetTime();
C Mac ANSI : pascal long MidiGetTime();
Pascal Mac : Function    MidiGetTime : longint;
Gfa Basic  : Function    midi_get_time : longint

Arguments
none

Result
The result is a 32-bit integer, the elapsed time in milliseconds
since the starting up of MidiShare.


Example (ANSI C)

A wait function :

void wait(long delay)
{
    long d;

    d = MidiGetTime() + delay;
    while (MidiGetTime() < d);
}



MidiGetVersion   


Description
Gives the version number of MidiShare


Prototype
C Atari    : short        MidiGetVersion();
C Mac ANSI : pascal short MidiGetVersion(void);
Pascal Mac : Function     MidiGetVersion : integer;
Gfa Basic  : Function     midi_get_version : integer

Arguments
none

Result
The result is a 16-bit integer, the MidiShare version number.
A result of 120 means <version 1.20>.


Example (ANSI C)

Print the MidiShare version number

void PrintVersion(void)
{
    printf( "MidiShare version : %4.2f\n", MidiGetVersion()/100.0);
}



MidiGrowSpace   


Description
try to increase the memory space of MidiShare.

Prototype
C Atari    : long        MidiGrowSpace( n);
C Mac ANSI : pascal long MidiGrowSpace( long n);
Pascal Mac : Function MidiGrowSpace( n : longint) : longint;
Gfa Basic  : <not implemented>

Arguments
n : the number of cells to increase the MidiShare memory space.


Result

The result is a 32-bit integer, the number of new cells actually
allocated.


Example (ANSI C)

Add 1000 cells to MidiShare memory space.

void TryGrowSpace(void)
{
   printf( "Try to allocate 1000 cells : %ld\n", MidiGrowSpace(1000));
}

Note : on the Atari, MidiGrowSpace can only be used from a desk
accessory, and not from a normal application.



MidiInt2ExtTime


Description
Convert an internal time in millisecond to an external time.
The convertion is made by adding the current offset between internal
and external time.


Prototype
C Atari    : long        MidiInt2ExtTime (time);
C Mac ANSI : pascal long MidiInt2ExtTime (long time)
Pascal Mac : Function    MidiGetExtTime( time : longint) : longint;
Gfa Basic  : Function    midi_int_2_ext_time(time%) : longint

Arguments
time : a 32-bits time in milliseconds

Result
the corresponding external time, a 32-bits value in milliseconds.


Note

When MidiShare is locked we have the following equivalence :

    MidiInt2ExtTime( MidiGetTime() ) == MidiGetExtTime()

We have also :

    TSyncInfo     myInfo;
    MidiGetSyncInfo(&myInfo);
    MidiInt2ExtTime(x) == x + myInfo.syncOffset



MidiIsConnected 


Description
Gives the state of a connection between two MidiShare applications.
Connections allow real-time communications of midi events between
applications.

Prototype
C Atari    : Boolean        MidiIsConnected( src, dest );
C Mac ANSI : pascal Boolean MidiIsConnected( short src, short dest );
Pascal Mac : Function MidiIsConnected( src, dest: integer) : boolean;
Gfa Basic  : Function midi_is_connected(src&,dest&) : boolean

Arguments
src  :     is the reference number of a source application
dest :     is the reference number of a destination application

Result
The result is true when a connection exist between the source and
the destination, and false otherwise.


Example (ANSI C)

Print all the sources of an application

void PrintSources(short refNum)
{
    short     src;
    short     i;

    printf( "Sources of : %s\n", MidiGetName( refNum) );
    for( i = 1; i <= MidiCountAppls(); ++i )
    {
        src = MidiGetIndAppl(i);
        if ( MidiIsConnected(src, refNum) )
            printf(" %i : %s \n", src, MidiGetName( src ) );
    }
}

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, the result of MidiGetName is a Pascal
string that must be converted to a C string to be printed.



MidiNewCell   


Description
Allocates a simple memory cell from the MidiShare memory manager. For
some special treatments, it may be useful to have access to the basic
functions of the memory manager. All the events managed by MidiShare
are implemented from fixed-sized cells (16 bytes).

Prototype
C Atari    : MidiEvPtr        MidiNewCell();
C Mac ANSI : pascal MidiEvPtr MidiNewCell(void);
Pascal Mac : Function         MidiNewCell : MidiEvPtr;
Gfa Basic  : Function         midi_new_cell : MidiEvPtr

Arguments
none

Result
The result a MidiEvPtr, a pointer to a memory cell, or NIL when
memory space is exhausted.


Example (ANSI C)

Allocate a new cell.

MidiEvPtr c;

c = MidiNewCell();

.....

MidiFreeCell(c);



Note : Cells allocated with MidiNewCell must be freed with
MidiFreeCell and not with MidiFreeEv.



MidiNewEv


Description
Allocates a new event of desirable type.

Prototype
C Atari    : MidiEvPtr        MidiNewEv( short typeNum );
C Mac ANSI : pascal MidiEvPtr MidiNewEv( short typeNum );
Pascal Mac : Function    MidiNewEv(typeNum: integer): MidiEvPtr;
Gfa Basic  : Function    midi_new_ev(typeNum&) : MidiEvPtr

Arguments
typeNum :     the type of event to be allocated

Result
The result a MidiEvPtr, a pointer to a MidiShare event of the
desired type, or NIL if the MidiShare memory space is exhausted.


Example (ANSI C)

A function for creating note events.


MidiEvPtr Note(long date, short pitch, short vel,
              long dur, short chan, short port)
{
    MidiEvPtr e;

    if ( e=MidiNewEv(typeNote) )
    {
        Date(e) = date; Pitch(e) = pitch; Vel(e) = vel;
        Dur(e) = dur; Chan(e) = chan; Port(e) = port;
    }
    return e;
}



MidiNewSeq   


Description
Allocation of a new empty sequence.

Prototype
C Atari    : MidiSeqPtr MidiNewSeq();
C Mac ANSI : pascal     MidiSeqPtr MidiNewSeq();
Pascal Mac : Function   MidiNewSeq : MidiSeqPtr;
Gfa Basic  : Function   midi_new_seq : MidiSeqPtr

Arguments
none

Result
The result is a MidiSeqPtr, a pointer to an empty sequence.


Example (ANSI C)

Create a sequence of 10 Midi clocks.


MidiSeqPtr ClockSeq()
{
    MidiSeqPtr    s;
    MidiEvPtr    e;
    long    d;

    s = MidiNewSeq();
    for (d=0; d< 2500; d+=250)
    {
        e = MidiNewEv (typeClock);
        Date(e) = d;
        MidiAddSeq (s, e);
    }
    return s;
}



MidiOpen       


Description
Opening of MidiShare. MidiOpen allows the recording of some
information relative to the application context (its name, the
value of the global data register, etc...), to allocate a reception
FIFO and to attribute a unique reference number to the application.
In counterpart to any MidiOpen call, the application must call the
MidiClose function before leaving, by giving its reference number
as an argument. MidiShare can thus be aware of the precise number
of active Midi applications.

Prototype
C Atari    : short        MidiOpen( applName );
C Mac ANSI : pascal short MidiOpen( MidiName applName );
Pascal Mac : Function     MidiOpen( applName: midiName ): integer;
Gfa Basic  : Function     midi_open(applName$) : integer

Arguments
applName :     the name of the application.

Result
The result is a unique reference number identifing the application.


Example (ANSI C)

A DoNothing MidiShare application.

#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
   if ( ! MidiShare() )     exit(1);   /* Check MidiShare loaded    */
   myRefNum = MidiOpen("Sample");      /* Ask for a reference number*/
   if ( myRefNum < 1 )     exit(1);    /* Check MidiOpen success    */
   printf( "refNum : %i \n", myRefNum);/* Print the reference number*/
   MidiClose(myRefNum);                /* And close                 */
}

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all strings passed as arguments of
a MidiShare function must be Pascal strings. In the previous exemple,
one must write :
myRefNum = MidiOpen("\pSample");



MidiReadSync


Description
The MidiReadSync function reads and sets to NIL a memory address.
This function is none-interruptible in order to make easier
communication between the application tasks that run at interrupt
level. It can be used to implement some sort of "mail boxe" in
conjunction of MidiWriteSync.

Prototype
C Atari    : Ptr          MidiReadSync( adrMem );
C Mac ANSI : pascal void *MidiReadSync( void* adrMem) ;
Pascal Mac : Function     MidiReadSync( adrMem: univ ptr): ptr;
Gfa Basic  : Function     midi_read_sync(adrMem%) : ptr

Arguments
adrMem :     the address of a variable containing a 32-bit data.

Result
The result is the content of the variable.

Side effect
Once read, the content of the variable is set to NIL.


Example (ANSI C)
                    << to be supplied >>



MidiSend     


Description
Sends an event. A copy of the event is sended to all the application
destinations. The date field of the event is used to specify when
destinations will actually receive the event.

Prototype
C Atari    : void        MidiSend( refNum, e );
C Mac ANSI : pascal void MidiSend( short refNum, MidiEvPtr e );
Pascal Mac : procedure   MidiSend( refNum: integer; e : MidiEvPtr);
Gfa Basic  : procedure   midi_send(refNum&,e%)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.


Example (ANSI C)

A receive alarm that processes all the received events by adding a
one second delay to their date.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n )
    {
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Activate the receive alarm */


Note : such a procedure can be called repeatedly in the main event
loop of the application, but for really accurate time control, it
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal
on the Macintosh. Consequently, in C, all procedure passed as
arguments of a MidiShare function must be declared as Pascal. In
the previous exemple, OneSecDelay must be declared as :
pascal void OneSecDelay (short refNum)



MidiSendAt    


Description
Sends an event. A copy of the event is sended to all the application
destinations. The date argument is used to specify when destinations
will actually receive the event.

Prototype
C Atari    : void        MidiSendAt( refNum, e );
C Mac ANSI : pascal void MidiSendAt( short refNum, MidiEvPtr e,
                                                        lond d );
Pascal Mac : procedure   MidiSendAt( refNum:integer; e:MidiEvPtr;
                                                      d:longint);
Gfa Basic  : procedure   midi_send_at(refNum&,e%,d%)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.
d       : a 32-bit integer, the date when destinations will
          receive the event.


Example (ANSI C)

Equivalence between MidiSend, MidiSendAt and MidiSendIm :

MidiSendAt(myRefNum,e,MidiGetTime());

    is equivalent to :

MidiSendIm(myRefNum,e);

    is equivalent to :

Date(e) = MidiGetTime();
MidiSend( myRefNum, e );



MidiSendIm


Description
Immediatly sends an event. A copy of the event is sended to all the
application destinations.

Prototype
C Atari    : void        MidiSendIm( refNum, e );
C Mac ANSI : pascal void MidiSendIm( short refNum, MidiEvPtr e );
Pascal Mac : procedure   MidiSendIm( refNum:integer; e:MidiEvPtr );
Gfa Basic  : procedure   midi_send_im(refNum&,e%)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
e       : a MidiEvePtr, it is a pointer to the event to send.


Example (ANSI C)

equivalence between MidiSend, MidiSendAt and MidiSendIm :


MidiSendIm(myRefNum,e);

    is equivalent to :

MidiSendAt(myRefNum,e,MidiGetTime());

    is equivalent to :

Date(e) = MidiGetTime();
MidiSend( myRefNum, e );



MidiSetApplAlarm    


Description
Defines the context alarm of an application. These alarm will be
called by MidiShare on every application global context modifications
(opening and closing of applications, opening and closing of midi
ports, changes in connections between applications).

Prototype
C Atari    : void        MidiSetApplAlarm(short refNum,
                                             ApplAlarmPtr alarm);
C Mac ANSI : pascal void MidiSetApplAlarm(short refNum,
                                             ApplAlarmPtr alarm);
Pascal Mac : Procedure   MidiSetApplAlarm(refNum:integer;
                                             alarm:ApplAlarmPtr);
Gfa Basic  : <not implemented> see note below

Arguments
refNum :    a 16-bit integer, it is the reference number of the
            application.
alarm  :    a ApplAlarmPtr, a  pointer to the application context
            alarm routine.

Prototype of a ApplAlarm routine
C Atari       : void        MyApplAlarm (refNum, code);
Turbo C Atari : void cdecl  MyApplAlarm (short refNum, long code);
C Mac ANSI    : pascal void MyApplAlarm (short refNum, long code);
Pascal Mac    : procedure   MyApplAlarm (refNum:integer; code:longint);


Argument of a ApplAlarm routine
refNum  : a 16-bit integer, it is the reference number of the
          application.
code    : a 32-bit integer, the context modification code.


Note for Gfa users : for Gfa Basic, it is a particular implementation
of this function named gfa_set_appl_alarm :
    procedure gfa_set_appl_alarm(refnum&,alarm_code%)
alarm_code% is a variable which will be set every time a global
context modification occur with the same meaning of the code passed
to the ApplAlarm routine. It is the responsability of the application
to detect if this variable changed.


Example (ANSI C)
                    << to be supplied >>



MidiSetField   


Description
Attributes a value to the i index data field of an event. The access
to the compulsory fields of the event is directly done. But the
access to the variables fields is achieved thru the MidiSetField
and MidiGetField functions. The procedure deals with the conversion
of this value into the concerned field format (8, 16 or 32-bit).

Prototype
C Atari    : void        MidiSetField( MidiEvPtr e, long f, long v);
C Mac ANSI : pascal void MidiSetField( MidiEvPtr e, long f, long v);
Pascal Mac : procedure   MidiSetField( e:MidiEvPtr; f:longint;
                                                   v:longint );
Gfa Basic  : procedure   midi_set_field(e%,f%,v%)

Arguments
e :     a MidiEvPtr, a pointer to the event to modifie
f :     a 32-bit integer, the index number of the field to modify
        ( from 0 to MidiCountFields(e)-1 )
v :     a 32-bit value to put in the field. This value will be
        converted to the right size (8, 16 or 32-bit)


Example (ANSI C)
                    << to be supplied >>



MidiSetFilter


Description
Associates a filter to an application. Each application can select
the events to be received by using a filter. The filtering process
is local to the application and has no influence on the events
received by the other applications. The implementation of these
filters is achieved by two routines : MidiSetFilter and MidiGetFilter.

Prototype
C Atari    : void        MidiSetFilter( refNum, filter );
C Mac ANSI : pascal void MidiSetFilter( short refNum,
                                         FilterPtr filter);
Pascal Mac : procedure   MidiSetFilter( refNum: integer;
                                         filter: FilterPtr );
Gfa Basic  : procedure   midi_set_filter(refNum&,filter%)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
filter  : a FilterPtr, a pointer to the application filter.


Example (ANSI C)
                    << to be supplied >>



MidiSetInfo   


Description
Defines the global information area of an application. The Macintosh
desk accessories cannot have global variables. To make up for this
drawback, the MidiSetInfo routine allows each application to define
a data area. This area remains accessible by MidiGetInfo function,
even during the alarm, and also serves as a global context to
desk accessories.

Prototype
C Atari    : void        MidiSetInfo( refNum, infoZone );
C Mac ANSI : pascal void MidiSetInfo( short refNum, void* infoZone );
Pascal Mac : procedure   MidiSetInfo( refNum: integer; infoZone: Ptr);
Gfa Basic  : procedure   midi_set_info(refNum&,infoZone%)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
infoZone : an arbitrary 32-bit value, generaly a pointer or a handle.


Example (ANSI C)
                    << to be supplied >>



MidiSetName   


Description
Changes the name of an application.

Prototype
C Atari    : void        MidiSetName( refNum, name );
C Mac ANSI : pascal void MidiSetName( short refNum, MidiName name );
Pascal Mac : procedure   MidiSetName( refNum: integer; name: midiName);
Gfa Basic  : procedure   midi_set_name(refNum&,name$)

Arguments
refNum  : a 16-bit integer, it is the reference number of the
          application.
name    : a MidiName, the new application name.


Example (ANSI C)
                    << to be supplied >>



MidiSetPortState


Description
Opening and closing of a Midi port. The implementation of Midi ports
is controlled by the MidiSetPortState and MidiGetPortState routines.
These must be used with care since they affect all the applications.
A closed port is available for other uses (printing, AppleTalk,
etc...). The Midi applications holding a "context alarm" will be
informed of this change in the ports state.

Prototype
C Atari    : void        MidiSetPortState( port, state );
C Mac ANSI : pascal void MidiSetPortState( short port, Boolean state);
Pascal Mac : procedure   MidiSetPortState( port: integer;
                                           state: boolean );
Gfa Basic  : procedure   midi_set_port_state(port&,state!)

Arguments
port  : a 16-bit integer, the port number to control.
state : a Boolean, True : to open a port, False : to close a port.


Example (ANSI C)
                    << to be supplied >>



MidiSetRcvAlarm


Description
Defines the event reception alarm of an application. The alarm will
be automatically called by MidiShare to inform the application of
the presence of new events in its reception fifo. This alarm is
always called under interruption. It must not use, directly or
indirectly, the Macintosh Memory Manager. It can freely access to
all the others MidiShare functions, particularly to the event
management (but not MidiOpen and MidiClose). It can also use
application global variables, since MidiShare restaures its global
context register, before the call.

Prototype of MidiSetRcvAlarm
C Atari    : void        MidiSetRcvAlarm( refNum, alarm );
C Mac ANSI : pascal void MidiSetRcvAlarm( short refNum,
                                             RcvAlarmPtr alarm );
Pascal Mac : Procedure   MidiSetRcvAlarm(refNum:integer;
                                            alarm:RcvAlarmPtr );
Gfa Basic  : <not implemented>

Arguments of MidiSetRcvAlarm
refNum : a 16-bit integer, the reference number of the application
alarm  : a RcvAlarmPtr, a pointer to a receive alarm routine or
         NIL to disable receive alarms.

Prototype of a RcvAlarm routine
C Atari       : void        MyRcvAlarm (refNum);
Turbo C Atari : void cdecl  MyRcvAlarm (short refNum);
C Mac ANSI    : pascal void MyRcvAlarm (short refNum);
Pascal Mac    : procedure   MyRcvAlarm (refNum:integer);

Argument of a RcvAlarm routine
refNum     : a 16-bit integer, it is the reference number of the
          application.


Example (ANSI C)

A receive alarm that processes all the received events by adding to
their date a one second delay.

void OneSecDelay (short refNum)
{
    MidiEvPtr    e;
    long n;

    for ( n = MidiCountEvs(refNum); n > 0; --n )
    {
        e = MidiGetEv(refNum);  /* Get an event from the fifo    */
        Date(e) += 1000;        /* Add 1000 ms to its date       */
        MidiSend(refNum,e);     /* Then send the event           */
    }
}

......

MidiSetRcvAlarm(myRefNum,OneSecDelay);/* Install the receive alarm */


Note : one such procedure can be called repeatedly in the main event
loop of the application, but for really accurate time control, it
must be installed as a receive alarm with MidiSetRcvAlarm.

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all procedure passed as arguments
of a MidiShare function must be declared as Pascal. In the previous
exemple, OneSecDelay must be declared as :
pascal void OneSecDelay (short refNum)



MidiSetSyncMode  


Description
Set the synchronisation mode of MidiShare.

Prototype
C Atari    : void        MidiSetSyncMode (mode);
C Mac ANSI : pascal void MidiSetSyncMode (unsigned short mode);
Pascal Mac : procedure   MidiSetSyncMode (mode: integer);
Gfa Basic  : procedure   midi_set_sync_mode(mode&)

Arguments
mode : an unsigned 16-bits word of struture : xa000000pppppppp.
x (bit 15) is used to choose between internal synchronisation (x=0)
   and external synchronisation (x=1)
a (bit 14) is used to choose between synchronisation on port p (a=0)
   and synchronisation on any port (a=1)
bit 13:8 are reserved for future use and must be set to 0.
p (bit 0:7) is the synchronisation port to be used when x=1 and a=0.
When a=1 the port number is ignored, the first port with incoming
MTC is used.


Example 1 (ANSI C)
Set the synchronisation to external, on any port.

    MidiSetSyncMode(MIDISyncExternal | MIDISyncAnyPort);


Example 2 (ANSI C)
Set the synchronisation to external, on port 18.

    MidiSetSyncMode(MIDISyncExternal | 18);


Example 3 (ANSI C)
Set the synchronisation to internal.

    MidiSetSyncMode(MIDISyncInternal);



MidiShare


Description
Tests MidiShare code presence in memory by trying to recognise a
special pattern. First of all, an application must make sure that
MidiShare is in memory. This test is done thanks to the MidiShare
function.

Prototype
C Atari    : Boolean        MidiShare();
C Mac ANSI : pascal Boolean MidiShare(void);
Pascal Mac : Function       MidiShare : boolean;
Gfa Basic  : Function       midi_share : boolean

Arguments
none

Result
The result is true when MidiShare is loaded, false otherwise.


Example (ANSI C)

A DoNothing MidiShare application.

#include MidiShare.h
#include <stdio.h>

short    myRefNum;

main()
{
   if ( ! MidiShare() )     exit(1);    /* Check MidiShare loaded */
   myRefNum = MidiOpen("Sample");       /* Ask for a ref. number  */
   if ( myRefNum < 1 )     exit(1);     /* Check MidiOpen success */
   printf( "refNum : %i \n", myRefNum); /* Print the ref. number  */
   MidiClose(myRefNum);                 /* And close              */
}

Note for Mac users : MidiShare was originaly developed for Pascal on
the Macintosh. Consequently, in C, all strings passed as arguments
of a MidiShare function must be Pascal strings. In the previous
exemple, one must write :
myRefNum = MidiOpen("\pSample");



MidiSmpte2Time     


Description
Convert an SMPTE location to a time in millisecond.


Prototype
C Atari    : long        MidiSmpte2Time (loc);
C Mac ANSI : pascal long MidiSmpte2Time (SmpteLocPtr loc);
Pascal Mac : Function    MidiSmpte2Time (loc: SmpteLocPtr): longint;
Gfa Basic  : Function    midi_smpte_2_time(loc%) : longint

Arguments
loc : a pointer to a TSmpteLocation record to be converted in
      milliseconds.

Result
a 32-bits time in milliseconds

Description of a TSmpteLocation

typedef struct TSmpteLocation *SmpteLocPtr;
typedef struct TSmpteLocation
{
     short    format;    // (0:24 f/s, 1:25 f/s, 2:30DF f/s, 3:30 f/s)
     short    hours;     // 0..23
     short    minutes;   // 0..59
     short    seconds;   // 0..59
     short    frames;    // 0..30 (according to format)
     short    fracs;     // 0..99 (1/100 of frames)
} TSmpteLocation;


Example (ANSI C)
Gives the SMPTE location from its current format to 30 drop frame
(format 2).

    TSmpteLocation myLoc;
...
// we suppose here myLoc filled with an Smpte location

    MidiTime2Smpte( MidiSmpte2Time(&myLoc), 2, &myLoc);

// now myLoc is filled with the same Smpte location but in 30 drop
frame format.



MidiTask        


Description
On the same way as MidiDTask, MidiTask allows to realize a time
delayed procedure call ; but on the reverse to MidiDTask, the call
is achieved under interruption as soon as falling time is due.


Prototype of MidiTask
C Atari    : MidiEvPtr MidiTask (MyProc, date, refNum, a1, a2, a3);
C Mac ANSI : pascal MidiEvPtr MidiTask (TaskPtr MyProc, long date,
                             short refNum, long a1, long a2, long a3);
Pascal Mac : Function MidiTask (MyProc:TaskPtr; date:longint;
                         refNum:integer; a1,a2,a3: longint):MidiEvPtr;
Gfa Basic  : <not implemented>


Arguments of MidiTask
MyProc   : a TaskPtr, it is the address of the routine to be called.
date     : a 32-bit integer, it is the date at which this call is
           scheduled.
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers left at the user's disposal, as
           arguments to MyProc


Result of MidiTask
The result, a MidiEvPtr, is a pointer to a typeProcess MidiShare
event. The result is NIL if MidiShare run out of memory.


Prototype of MyProc
C Atari       : void        MyProc (date, refNum, a1, a2, a3);
Turbo C Atari : void cdecl  MyProc (long date, short refNum,
                                    long a1, long a2, long a3);
C Mac ANSI    : pascal void MyProc (long date, short refNum,
                                    long a1, long a2, long a3);
Pascal Mac    : procedure   MyProc (date:longint; refNum:integer;
                                               a1,a2,a3: longint);

Argument of MyProc
date     : a 32-bit integer, it is the date of the call .
refNum   : a 16-bit integer, it is the reference number of the
           application.
a1,a2,a3 : are 32-bit integers that can be freely used.


Example (ANSI C)

Schedule a procedure Action() call 1000 ms ahead.


MidiEvPtr    myTask;

myTask = MidiTask(Action,MidiGetTime()+1000,myRefNum, a1, a2, a3);

Note : The result, in myTask, can be used to test the success of
MidiTask. It can also be used by MidiForgetTask to try to "forget"
a scheduled task before it happens.



MidiTime2Smpte


Description
Convert a time in millisecond to an SMPTE location.


Prototype
C Atari    : void        MidiTime2Smpte (time, format, loc);
C Mac ANSI : pascal void MidiTime2Smpte (long time, short format,
                                         SmpteLocPtr loc);
Pascal Mac : procedure   MidiTime2Smpte (time:longint; format:integer;
                                          loc: SmpteLocPtr);
Gfa Basic  : procedure   midi_time_2_smpte(time%,format&,loc%)

Arguments
time  : a 32-bits time in milliseconds to convert in an Smpte location
format: a 16-bits integer, the Smpte format to be used : (0 : 24 f/s,
         1 : 25 f/s, 2 : 30DF f/s, 3 : 30 f/s)
loc   : a pointer to a TSmpteLocation record to be filled with the
         resulting Smpte location.


Description of a TSmpteLocation

typedef struct TSmpteLocation *SmpteLocPtr;
typedef struct TSmpteLocation
{
     short    format;  // (0:24 f/s, 1:25 f/s, 2:30DF f/s, 3:30 f/s)
     short    hours;   // 0..23
     short    minutes; // 0..59
     short    seconds; // 0..59
     short    frames;  // 0..30 (according to format)
     short    fracs;   // 0..99 (1/100 of frames)
} TSmpteLocation;


Example (ANSI C)
Gives the SMPTE start location of the tape.

    TSyncInfo     myInfo;
    TSmpteLocation myLoc;

    MidiGetSyncInfo(&myInfo);
    MidiTime2Smpte( MidiInt2ExtTime(myInfo.syncStart),
                        myInfo.syncFormat, &myLoc);



MidiTotalSpace    


Description
Gives the total space. MidiTotalSpace allows to know at any time the
total number of cells allocated by the MidiShare memory manager at
startup.

Prototype
C Atari    : long        MidiTotalSpace();
C Mac ANSI : pascal long MidiTotalSpace(void);
Pascal Mac : Function    MidiTotalSpace : longint;
Gfa Basic  : Function    midi_total_space : longint

Arguments
none

Result
the result is a 32-bit integer, the total number of cells in the
MidiShare memory manager.


Example (ANSI C)

Print informations about MidiShare memory space.

void PrintMemInfo(void)
{
 printf("MidiShare memory :\n");
 printf("free space  : %i cells\n", MidiFreeSpace());
 printf("used space  : %i cells\n", MidiTotalSpace()-MidiFreeSpace());
 printf("total space : %i cells\n", MidiTotalSpace());
}



MidiWriteSync


Description
Writes a 32-bit value to a variable only if the previous variable
content was NIL. This function is non-interruptible in order to make
easier communication between the application tasks that run at
interrupt level. It can be used to implement some sort of "mail boxes"
in conjunction of MidiReadSync.

Prototype
C Atari    : Ptr          MidiWriteSync( adrMem, val );
C Mac ANSI : pascal void* MidiWriteSync( void *adrMem, void *val );
Pascal Mac : Function     MidiWriteSync( adrMem:univ ptr;
                                            val:univ ptr):ptr;
Gfa Basic  : Function     midi_write_sync(adrMem%,val%)

Arguments
adrMem :     is the addresse of a variable to modifie.
val    :     is a 32-bit value to write.

Result
The result is the previous content of the variable.


Example (ANSI C)
                    << to be supplied >>



EVENT'S TYPES



typeActiveSens   	(code 15)    


Event Description
A Real Time ActiveSens message.

Fields : ActiveSens events have no field.


Example (ANSI C)
Creates a ActiveSens event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr ActiveSens ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeActiveSens ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date; /* These informations are common to all*/
        Port(e) = port; /* kind of events */
    }
    return e;
}



typeChanPress   	(code 6)


Event Description
A Channel pressure message with pressure value.

Fields : ChanPress events have 1 field numbered 0 :

    0 - A channel pressure value from 0 to 127. (Field size : 1 byte)


Example (ANSI C)
Creates a ChanPress event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr ChanPress( long date, short press, short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeChanPress ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,press); /* Field particular to ChanPress */
    }
    return e;
}



typeClock             	(code 10)                    


Event Description
A Real Time Clock message.

Fields : Clock events have no field.


Example (ANSI C)
Creates a Clock event. Return a pointer to the event or NIL if there
is no more memory space.

MidiEvPtr Clock ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeClock ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}



typeContinue      	(code 12)


Event Description
A Real Time Continue message.

Fields : Continue events have no field.


Example (ANSI C)
Creates a Continue event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr Continue ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeContinue ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}



typeCopyright      	(code 136)                  


Event Description
A copyright event (from the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeCopyright events have a variable number of character
         fields.


Example 1 (ANSI C)
Creates a typeCopyright event from a character string. Return a
pointer to the event or NIL if there is not enough memory space.

MidiEvPtr Copyright ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeCopyright) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;      /* These informations are common to all */
        Chan(e) = chan;      /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the event while counting the*/
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)) {
        /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeCopyright event into a character string.
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeCtrl14b       	(code 131)


Event Description
A Control Change event with a controller number form 0 to 31 and
a 14-bits value. When a typeCtrl14b event is sent to external Midi
devices, actually two control change messages are sent, the first one
for the MSB part of the value and the second one for the LSB part of
the value. The message for the LSB part is sent only when the LSB part
of the value is different from 0.

Fields : Ctrl14b events have 2 fields numbered from 0 to 1 :

    0 - A control number from 0 to 31. (Field size : 2 byte)
    1 - A control value from 0 to 16383. (Field size : 2 byte)


Example (ANSI C)
Creates a CtrlChange event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr CtrlChange14b( long date, short ctrl, short val, short chan,
                         short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeCtrl14b ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events  */
        Port(e) = port;
        MidiSetField(e,0,ctrl); /* Fields particular to CtrlChange  */
        MidiSetField(e,1,val);
    }
    return e;
}



typeCtrlChange   	(code 4)                      


Event Description
A Control Change message with controller and value.

Fields : CtrlChange events have 2 fields numbered from 0 to 1 :

    0 - A control number from 0 to 127. (Field size : 1 byte)
    1 - A control value from 0 to 127. (Field size : 1 byte)


Example (ANSI C)
Creates a CtrlChange event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr CtrlChange( long date, short ctrl, short val, short chan,
                      short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeCtrlChange ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,ctrl); /* Fields particular to CtrlChange */
        MidiSetField(e,1,val);
    }
    return e;
}



typeChanPrefix    	(code 142)


Event Description
A channel prefix event (from the MidiFile 1.0 specification). This
event cannot be sent to external Midi devices.

Fields : typeChanPrefix events have one field.

    0 - A channel prefix number from 0 to 15. (Field size : 1 byte)


Example (ANSI C)
Creates a typeChanPrefix event. Return a pointer to the event or NIL
if there is not enough memory space.

MidiEvPtr ChanPrefix ( long date, short prefix)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeChanPrefix))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
        MidiSetField( e, 0, prefix);
    }
    return e;
}



typeCuePoint       	(code 141)                 


Event Description
A cue point event (from the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeCuePoint events have a variable number of character fields.


Example 1 (ANSI C)
Creates a typeCuePoint event from a character string. Return a pointer
to the event or NIL if there is not enough memory space.

MidiEvPtr CuePoint ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeCuePoint))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}

Example 2 (ANSI C)
Convert a typeCuePoint event into a character string.
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeDProcess      	(code 129)


Event Description
DProcess events are automatically created by MidiDTask. They are used
to realize time delayed procedure call. Once the scheduling date is
due, the routine is not automatically executed, but stored in a special
list.It is the application responsability to execute, one by one, those
pending tasks using MidiExec1DTask.

Fields : DProcess events have 4 fields numbered from 0 to 3 :

    0 - a TaskPtr, the adress of the procedure to call.
        (Field size:4 byte)
    1 - the first argument of the procedure. (Field size : 4 byte)
    2 - the second argument of the procedure. (Field size : 4 byte)
    3 - the third argument of the procedure. (Field size : 4 byte)


Example (ANSI C)
Creates a DProcess event in the same way than MidiDTask.

MidiEvPtr MakeDTask ( TaskPtr proc, long date, short refNum, long arg1,
                    long arg2, long arg3)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeDProcess ) )
    /* Allocate a new event. Check not NIL */
    {
        MidiSetField(e, 0, (long)proc); /* Fill the 4 fields */
        MidiSetField(e, 1, arg1);
        MidiSetField(e, 2, arg2);
        MidiSetField(e, 3, arg3);
        MidiSendAt(refNum, e, date); /* and schedule the differed task*/
    }
    return e;
}



typeEndTrack      	(code 143)                 


Event Description
An end of track event (from the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeEndTrack  events have no field.


Example (ANSI C)
Creates a typeEndTrack  event. Return a pointer to the event or NIL
if there is not enough memory space.

MidiEvPtr EndTrack ( long date )
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeEndTrack))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
    }
    return e;
}



typeInstrName     	(code 138)


Event Description
An instrument name event (from the MidiFile 1.0 specification). This
event cannot be sent to external Midi devices.

Fields : typeInstrName events have a variable number of character
         fields.


Example 1 (ANSI C)
Creates a typeInstrName event from a character string. Return a pointer
to the event or NIL if there is not enough memory space.

MidiEvPtr InstrName ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeInstrName) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the event while counting the*/
            MidiAddField(e ,*s); /* characters of the original string */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);       /* if we run out of memory : free the*/
            return 0;            /* event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeInstrName event into a character string.
Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeKeyOff           	(code 2)                     


Event Description
A Note Off message with pitch and velocity.

Fields : KeyOff events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)


Example 1 (ANSI C)
Creates a KeyOff event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using MidiSetField instead
of direct structure access.

MidiEvPtr KeyOff(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOff ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyOff*/
        MidiSetField(e,1,vel);
    }
    return e;
}


Example 2 (ANSI C)
Creates a KeyOff event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using direct structure
access instead of MidiSetField.

MidiEvPtr KeyKeyOff(long date,short pitch,short vel,short chan,
                    short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOff ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;   /* These fields are particular to KeyOff*/
        Vel(e)  = vel;
    }
    return e;
}



typeKeyOn         	(code 1)


Event Description
A Note On message with pitch and velocity.

Fields : KeyOn events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)


Example 1 (ANSI C)
Creates a KeyOn event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using MidiSetField
instead of direct structure access.

MidiEvPtr KeyOn(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOn ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyOn*/
        MidiSetField(e,1,vel);
    }
    return e;
}


Example 2 (ANSI C)
Creates a KeyOn event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using direct structure
access instead of MidiSetField.

MidiEvPtr KeyOn(long date,short pitch,short vel,short chan,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyOn ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;   /* These fields are particular to KeyOn */
        Vel(e)  = vel;
    }
    return e;
}



typeKeyPress      	(code 3)                     


Event Description
A Polyphonic Key Pressure message with pitch and pressure.

Fields : KeyPress events have 2 fields numbered from 0 to 1 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Press, a key pressure from 0 to 127. (Field size : 1 byte)


Example 1 (ANSI C)
Creates a KeyPress event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using MidiSetField instead
of direct structure access.

MidiEvPtr KeyPress(long date,short pitch,short press,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyPress ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch);/*These fields are particular to KeyPress*/
        MidiSetField(e,1,press);
    }
    return e;
}


Example 2 (ANSI C)
Creates a KeyPress event. Return a pointer to the event or NIL if there
is no more memory space. Fields are modified using direct structure
access instead of MidiSetField.

MidiEvPtr KeyPress(long date,short pitch,short press,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeKeyPress ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch;  /* These fields are particular to KeyPress*/
        Vel(e)  = press;   /* Same byte than velocity */
    }
    return e;
}



typeKeySign       	(code 147)


Event Description
A Key Signature event (form the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeKeySign events have 2 fields :

    0 - from -7 (7 flats) to 7 (7 sharps), (8-bits field)
    1 - form 0 (major key) to 1 (minor key), (8-bits field)


Example (ANSI C)
Creates a Key Signature event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr KeySign (long date, long sharpflats, long minor)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeKeySign))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
        MidiSetField(e, 0, sharpflats);
        MidiSetField(e, 1, minor);
    }
    return e;
}



typeLyric               	(code 139)                


Event Description
A lyric event (from the MidiFile 1.0 specification). This event cannot
be sent to external Midi devices.

Fields : typeLyric events have a variable number of character fields.


Example 1 (ANSI C)
Creates a typeLyric event from a character string. Return a pointer to
the event or NIL if there is not enough memory space.

MidiEvPtr Lyric ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeLyric) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s);/* characters of the original string  */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);  /* if we run out of memory : free the */
            return 0;       /* event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeLyric event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeMarker        	(code 140)


Event Description
A marker event (from the MidiFile 1.0 specification). This event cannot
be sent to external Midi devices.

Fields : typeMarker events have a variable number of character fields.


Example 1 (ANSI C)
Creates a typeMarker event from a character string. Return a pointer
to the event or NIL if there is not enough memory space.

MidiEvPtr Marker ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv(typeMarker))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the */
            MidiAddField(e ,*s);/* characters of the original string  */
        if (c != MidiCountFields(e)){ /* Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the */
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeMarker event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeNonRegParam  (code 132)          


Event Description
A Non Registred Parameter event with a 14-bits parameter number and
a 14-bits parameter value. When a typeNonRegParam event is sent to
external Midi devices, actually four control change messages are sent,
two to select the non-registerd parameter number, and two for the
parameter value using the 14-bits data-entry controller.

Fields : typeNonRegParam events have 2 fields numbered from 0 to 1 :

    0 - A Non Registred Parameter number from 0 to 16383.
       (Field size : 2 byte)
    1 - A parameter value from 0 to 16383. (Field size : 2 byte)


Example (ANSI C)
Creates a Non Registred Parameter event. Return a pointer to the event
or NIL if there is no more memory space.

MidiEvPtr NonRegParam(long date,short param,short val,short chan,
                      short port)
{
    MidiEvPtr e;

    if (e = MidiNewEv(typeNonRegParam))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,param); /* Fields particular to NonRegParam */
        MidiSetField(e,1,val);
    }
    return e;
}



typeNote          	(code 0)


Event Description
A note with pitch, velocity and duration. When a Note event is sent to
external Midi devices, actually a NoteOn message is first sent followed,
after a delay specified by the duration, by a NoteOn with a velocity
of 0 to end the note.

Fields : Note events have 3 fields numbered from 0 to 2 :

    0 - Pitch, a note number from 0 to 127. (Field size : 1 byte)
    1 - Vel, a note velocity from 0 to 127. (Field size : 1 byte)
    2 - Dur, a note duration from 0 to 215-1. (Field size : 2 bytes)


Example 1 (ANSI C)
Creates a Note event. Return a pointer to the event or NIL if there is
no more memory space. Fields are modified using MidiSetField instead of
direct structure access.

MidiEvPtr Note(long date,short pitch,short vel,short duration,
               short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeNote ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,pitch); /*These fields are particular to Notes*/
        MidiSetField(e,1,vel);
        MidiSetField(e,2,dur);
    }
    return e;
}


Example 2 (ANSI C)
Creates a Note event. Return a pointer to the event or NIL if there is
no more memory space. Fields are modified using direct structure access
instead of MidiSetField.

MidiEvPtr Note(long date,short pitch,short vel,short duration,
               short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeNote ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;   /* These informations are common to all */
        Chan(e) = chan;   /* kind of events */
        Port(e) = port;
        Pitch(e) = pitch; /* These fields are particular to Notes */
        Vel(e)  = vel;
        Dur(e)  = dur;
    }
    return e;
}



typePitchWheel   	(code 7)                     


Event Description
A Pitch Bender message with a 14 bits resolution.

Fields : PitchWheel events have 2 fields numbered from 0 to 1 :

    0 - LS 7-Bits of 14-bits pitch swing, from 0 to 127.
        (Field size : 1 byte)
    1 - MS 7-Bits of 14-bits pitch swing, from 0 to 127.
        (Field size : 1 byte)


Example (ANSI C)
Creates a PitchWheel  event with a parameter between -8192 and 8191.
Return a pointer to the event or NIL if there is no more memory space.

MidiEvPtr PitchWheel( long date, short wheel, short chan, short port)
{
    const offset = 8192;
    const min = -8192;
    const max = 8191;
    MidiEvPtr e;

    wheel = (wheel>max) ? max : (wheel<min) ? min : wheel;

    if ( e = MidiNewEv( typePitchWheel ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,(wheel+offset) & 0x7F);    /*LS-7bits Field*/
        MidiSetField(e,1,(wheel+offset)>>7 & 0x7F); /*MS-7bits Field*/
    }
    return e;
}



typePrivate       	(code 19 to 127)


Event Description
A private event with 4 fields which can be freely used by the
application. Sends only to the application who owned it.

Fields : Private events have 4 fields numbered from 0 to 3.
         Fields size : 4 bytes.


Example (ANSI C)
<to be supplied>



typeProcess         	(code 128)                


Event Description
Process events are automatically created by MidiCall and MidiTask.
They are used to realize time delayed procedure call. The procedure
call is achieved under interrupts as soon as the scheduling date
is due.

Fields : Process events have 4 fields numbered from 0 to 3 :

    0 - a TaskPtr, the adress of the procedure to call.
        (Field size:4 byte)
    1 - the first argument of the procedure. (Field size : 4 byte)
    2 - the second argument of the procedure. (Field size : 4 byte)
    3 - the third argument of the procedure. (Field size : 4 byte)


Example (ANSI C)
Creates a Process event in the same way than MidiTask.

MidiEvPtr MakeTask ( TaskPtr proc, long date, short refNum, long arg1,
                    long arg2, long arg3)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeProcess ) )
    /* Allocate a new event. Check not NIL */
    {
        MidiSetField(e, 0, (long)proc); /* Fill the 4 fields */
        MidiSetField(e, 1, arg1);
        MidiSetField(e, 2, arg2);
        MidiSetField(e, 3, arg3);
        MidiSendAt(refNum, e, date);    /* and schedule the task */
    }
    return e;
}



typeProgChange    	(code 5)


Event Description
A Program Change message with a program number.

Fields : ProgChange events have 1 field numbered 0 :

    0 - A program number from 0 to 127. (Field size : 1 byte)


Example (ANSI C)
Creates a ProgChange event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr ProgChange( long date, short prog, short chan, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeProgChange ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,prog); /* Field particular to ProgChange */
    }
    return e;
}



typeQuarterFrame  	(code 130)            


Event Description
A Midi time code quarter frame message with message type and value.
These two fields are automatically assembled by MidiShare into one byte
when the message is sent.

Fields : QuarterFrame events have 2 fields numbered from 0 to 1 :

    0 - A message type from 0=Frame count LSB nibble to 7=Hours
        count MS nibble. (Field size : 1 byte)
    1 - A count nibble from 0 to 15. (Field size : 1 byte)


Example (ANSI C)
Creates a QuarterFrame event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr QuarterFrame( long date, short type, short nibble,short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeQuarterFrame ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
        MidiSetField(e,0,type); /* Fields particular to QuarterFrame */
        MidiSetField(e,1,nibble);
    }
    return e;
}



typeRegParam      	(code 133)


Event Description
A Registred Parameter event with a 14-bits parameter number and a
14-bits parameter value. When a typeRegParam event is sent to external
Midi devices, actually four control change messages are sent, two to
select the registred parameter number, and two for the parameter value
using the 14-bits data-entry controller.

Fields : typeRegParam events have 2 fields numbered from 0 to 1 :

    0 - A Registred Parameter number from 0 to 16383.
        (Field size : 2 byte)
    1 - A Registerd Parameter value from 0 to 16383.
        (Field size : 2 byte)


Example (ANSI C)
Creates a Registred Parameter event. Return a pointer to the event or
NIL if there is no more memory space.

MidiEvPtr RegParam(long date,short param,short val,short chan,
                   short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeRegParam ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;     /* These informations are common to all */
        Chan(e) = chan;     /* kind of events */
        Port(e) = port;
        MidiSetField(e,0,param); /* Fields particular to RegParam */
        MidiSetField(e,1,val);
    }
    return e;
}



typeReserved      	(code 149 to 254)    


Event Description
These events are reserved for future use.



typeReset         	(code 16)


Event Description
A Real Time Reset message.

Fields : Reset events have no field.


Example (ANSI C)
Creates a Reset event. Return a pointer to the event or NIL if there
is no more memory space.

MidiEvPtr Reset ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeReset ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}




typeSeqName     	(code 137)                


Event Description
A sequence name event (from the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeSeqName events have a variable number of character fields.


Example 1 (ANSI C)
Creates a typeSeqName event from a character string. Return a pointer
to the event or NIL if there is not enough memory space.

MidiEvPtr SeqName ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv( typeSeqName ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++) /* Build the event while counting the*/
            MidiAddField(e ,*s);/* characters of the original string */
        if (c != MidiCountFields(e)){ /*Check the length of the event*/
            MidiFreeEv(e);      /* if we run out of memory : free the*/
            return 0;           /* event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeSeqName event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeSeqNum        	(code 134)


Event Description
A Sequence number event (form the MidiFile 1.0 specification).
This event cannot be sent to external Midi devices.

Fields : typeSeqNum events have 1 field :

    0 - Sequence number form 0 to 65535 (2-bytes field)


Example (ANSI C)
Creates a Sequence Number event. Return a pointer to the event or NIL
if there is no more memory space.

MidiEvPtr SeqNum( long date, short num, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeSeqNum) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,num); /* the sequence number field */
    }
    return e;
}



typeSMPTEOffset   	(code 145)           


Event Description
An SMPTE Offset event (form the MidiFile 1.0 specification). This event
cannot be sent to external Midi devices.

Fields : typeSMPTEOffset events have 2 fields :

    0 - Hours, minutes and seconds parts of the SMPTE Offset in seconds
        from 0 to 1048575 (20-bits field)
    1 - Frames and 100ths of a frame part of the SMPTE Offset in 100ths
        of a frame form 0 to 4095 (12-bits field)


Example 1 (ANSI C)
Creates an SMPTE Offset event. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr SMPTEOffset(long hr,long mn,long sec,long frames,
                      long subframes)
{
    MidiEvPtr e;

    if (e = MidiNewEv(typeSMPTEOffset))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = 0;
        MidiSetField(e, 0, hr*3600 + mn*60 + sec);
        MidiSetField(e, 1, (frames*100 + subframes));
    }
    return e;
}


Example 2 (ANSI C)
Read the different parts of an SMPTE Offset event.

long GetHours (MidiEvPtr e)
{
    return MidiGetField(e,0) / 3600;
}

long GetMinutes (MidiEvPtr e)
{
    return MidiGetField(e,0) % 3600 / 60;
}

long GetSeconds (MidiEvPtr e)
{
    return MidiGetField(e,0) % 60;
}

long GetFrames (MidiEvPtr e)
{
    return MidiGetField(e,1) / 100;
}

long GetSubFrames (MidiEvPtr e)
{
    return MidiGetField(e,1) % 100;
}



typeSongPos       	(code 8)


Event Description
A Song Position Pointer message with a 14 bits location
(unit : 6 Midi Clocks).

Fields : SongPos events have 2 fields numbered from 0 to 1 :

    0 - LS 7-Bits of 14-bits location, from 0 to 127.
        (Field size : 1 byte)
    1 - MS 7-Bits of 14-bits location, from 0 to 127.
        (Field size : 1 byte)


Example (ANSI C)
Creates a SongPos  event with a location in Midi clocks. The location
is internaly divided by 6. Return a pointer to the event or NIL if
there is no more memory space.

MidiEvPtr SongPos( long date, short pos, short port)
{
    MidiEvPtr e;

    pos = pos / 6;

    if ( e = MidiNewEv( typeSongPos) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,pos & 0x7F);    /* LS-7bits Field */
        MidiSetField(e,1,pos>>7 & 0x7F); /* MS-7bits Field */
    }
    return e;
}



typeSongSel        	(code 9)


Event Description
A Song Select message with a song number.

Fields : SongSel events have 1 field numbered 0 :

    0 - A song number from 0 to 127. (Field size : 1 byte)


Example (ANSI C)
Creates a SongSel event. Return a pointer to the event or NIL if there
is no more memory space.

MidiEvPtr SongSel ( long date, short song, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeSongSel ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Port(e) = port;    /* kind of events */
        MidiSetField(e,0,song); /* Field particular to SongSel */
    }
    return e;
}



typeSpecific      	(code 148)


Event Description
A sequencer specific event (from the MidiFile 1.0 specification). This
event cannot be sent to external Midi devices.

Fields : typeSpecific events have a variable number of 8-bits fields.


Example (ANSI C)
Creates a typeSpecific event from an array of bytes. Return a pointer
to the event or NIL if there is no more memory space.

MidiEvPtr Specific ( long date, short len, Byte *p)
{
    MidiEvPtr e;
    short    c;

    if ( e = MidiNewEv( typeStream ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
        c = len;
        while (c--) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /*if event smaller than len then*/
        {
            MidiFreeEv(e);  /* we run out of memory, free it */
            e = nil;        /* and return nil */
        }
    }
    return e;
}



typeStart              	(code 11)                  


Event Description
A Real Time Start message.

Fields : Start events have no field.


Example (ANSI C)
Creates a Start event. Return a pointer to the event or NIL if there
is no more memory space.

MidiEvPtr Start ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeStart ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
    }
    return e;
}



typeStop          	(code 13)


Event Description
A Real Time Stop message.

Fields : Stop events have no field.


Example (ANSI C)
Creates a Stop event. Return a pointer to the event or NIL if there is
no more memory space.

MidiEvPtr Stop ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeStop ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}



typeStream          	(code 18)                  


Event Description
Stream message are arbitrary stream of bytes sent by the MidiShare
driver without any processing.

Fields : Stream events have a variable number of fields.


Example (ANSI C)
Creates a Stream event from an array of short. Return a pointer to the
event or NIL if there is no more memory space.

MidiEvPtr Stream ( long date, short len, short *p, short port)
{
    MidiEvPtr e;
    short c;

    if ( e = MidiNewEv( typeStream ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;   /* These informations are common to all */
        Port(e) = port;   /* kind of events */
        c = len+1;
        while (--c) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /* if event smaller than len then*/
        {
            MidiFreeEv(e);   /* we run out of memory, free it */
            e = nil;         /* and return nil */
        }
    }
    return e;
}



typeSysEx         	(code 17)


Event Description
A System Exclusive message.

Fields : SysEx events have a variable number of fields. The leading F0
and tailing F7 codes must not be included. They are automatically
supplied by MidiShare. The channel field of the event is ORed with the
first data byte after the manufacturer ID. This works for setting the
channel of many system exclusive messages.


Example (ANSI C)
Creates a SysEx event from an array of short. Return a pointer to the
event or NIL if there is no more memory space.

MidiEvPtr SysEx ( long date, short len, short *p, short chan,
                  short port)
{
    MidiEvPtr e;
    short c;

    if ( e = MidiNewEv( typeSysEx ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        c = len+1;
        while (--c) MidiAddField(e,*p++);
        if (MidiCountFields(e) < len ) /* if event smaller than len then*/
        {
            MidiFreeEv(e);   /* we run out of memory, free it */
            e = nil;         /* and return nil */
        }
    }
    return e;
}



typeTempo           	(code 144)               


Event Description
A tempo event (from the MidiFile 1.0 specification). This event cannot
be sent to external Midi devices.

Fields : typeTempo  events have one field.

     0 - A tempo value in microseconds/Midi quarter-note 0 to 127.
         (Field size : 4 bytes)


Example 1 (ANSI C)
Creates a typeTempo event from a floating point tempo value in
quarter-notes per minutes. Return a pointer to the event or NIL if
there is not enough memory space.

MidiEvPtr TempoChange ( long date, float tempo)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeTempo))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
        MidiSetField(e, 0, (long)(60000000.0 / tempo));
    }
    return e;
}


Example 2 (ANSI C)
Convert a tempo event in microseconds per quarter-note in a floating
point tempo value in quarter-notes per minutes.

float GetTempo (MidiEvPtr e)
{
    return 60000000.0 / (float) MidiGetField(e,0);
}



typeText          	(code 135)


Event Description
A text event (from the MidiFile 1.0 specification). This event cannot
be sent to external Midi devices.

Fields : typeText events have a variable number of character fields.


Example 1 (ANSI C)
Creates a typeText event from a character string. Return a pointer to
the event or NIL if there is not enough memory space.

MidiEvPtr Text ( long date, char *s, short chan, short port)
{
    MidiEvPtr e;
    long    c=0;

    if ( e = MidiNewEv( typeText ) )
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;    /* These informations are common to all */
        Chan(e) = chan;    /* kind of events */
        Port(e) = port;
        for (c=0; *s; s++, c++)  /* Build the text event while counting  */
            MidiAddField(e ,*s); /* the characters of the original string */
        if (c != MidiCountFields(e)){/* Check the length of the text event*/
            MidiFreeEv(e);    /* if we run out of memory : free the */
            return 0;         /* text event and return NIL */
        }
    }
    return e;
}


Example 2 (ANSI C)
Convert a typeText event into a character string. Assume s big enough.

void GetText (MidiEvPtr e, char *s)
{
    short c=0, i=0;

    c = MidiCountFields(e);
    while (i<c) *s++ = MidiGetField(e, i++);
    *s = 0;
}



typeTimeSign      	(code 146)                


Event Description
A Time Signature event (from the MidiFile 1.0 specification). This
event cannot be sent to external Midi devices.

Fields : typeTimeSign events have 4 fields :

    0 - Numerator (8-bits field)
    1 - denominator in power of two (8-bits field)
    2 - Midi Clocks per metronome clicks (8-bits field)
    3 - notated 32th of note per quarter-note (8-bits field)


Example (ANSI C)
Creates a Time Signature event. Return a pointer to the event or NIL
if there is no more memory space.

MidiEvPtr TimeSign (long date, long num, long denom, long click,
                    long quarterDef)
{
    MidiEvPtr e;

    if ( e = MidiNewEv(typeTimeSign))
    /* Allocate a new event. Check not NIL */
    {
        Date(e) = date;
        MidiSetField(e, 0, num);
        MidiSetField(e, 1, denom);
        MidiSetField(e, 2, click);
        MidiSetField(e, 3, quarterDef);
    }
    return e;
}



typeTune          	(code 14)


Event Description
A Tune message.

Fields : Tune events have no field.


Example (ANSI C)
Creates a Tune event. Return a pointer to the event or NIL if there is
no more memory space.

MidiEvPtr Tune ( long date, short port)
{
    MidiEvPtr e;

    if ( e = MidiNewEv( typeTune ) )
    /* Allocate a new event. Check not NIL*/
    {
        Date(e) = date;  /* These informations are common to all */
        Port(e) = port;  /* kind of events */
    }
    return e;
}



 STRUCTURE


MidiSEXPtr

typedef struct TMidiSEX *MidiSEXPtr;

typedef struct TMidiSEX
{
    MidiSEXPtr link;   /* link to next cell */
    Byte data[12];     /* 12 data bytes     */
} TMidiSEX;



MidiSTPtr
 
typedef struct TMidiST *MidiSTPtr;

typedef struct TMidiST
{
    Ptr ptr1;   /* 4 32-bits fields */
    Ptr ptr2;
    Ptr ptr3;
    Ptr ptr4;
} TMidiST;



MidiEvPtr

typedef struct TMidiEv *MidiEvPtr;

typedef struct TMidiEv
{
    MidiEvPtr link;       /* link to next event      */
    unsigned long date;   /* event date (in ms)      */
    Byte evType;          /* event type              */
    Byte refNum;          /* sender reference number */
    Byte port;            /* Midi port               */
    Byte chan;            /* Midi channel            */
    union {               /* info depending of event type : */
        struct {              /* for notes    */
            Byte pitch;           /* pitch    */
            Byte vel;             /* velocity */
            unsigned short dur;   /* duration */
        } note;

        struct {              /* for MidiFile time signature  */
            Byte numerator;       /* numerator                */
            Byte denominator;     /* denominator as neg power */
                                  /* of 2. (2= quarter note)  */
            Byte nClocks;         /* number of Midi clocks in */
                                  /* a metronome click        */
            Byte n32nd;           /* number of 32nd notes in  */
                                  /* a Midi quarter note      */
        } timeSign;

        struct {              /* for MidiFile key signature */
            char ton;             /* 0: key of C, 1: 1 sharp */
                                  /* -1: 1 flat etc...       */
            Byte mode;            /* 0: major 1: minor       */
            Byte unused[2];
        } keySign;

        struct {              /* for MidiFile sequence number */
            unsigned short number;
            short unused;
        } seqNum;
        long tempo;            /* MidiFile tempo in            */
                               /* microsec/Midi quarter note   */
        Byte data[4];          /* for other small events       */
        MidiSEXPtr linkSE;     /* link to last sysex extension */
        MidiSTPtr linkST;      /* link to private extension    */
    } info;
} TMidiEv;



MidiSeqPtr

typedef struct TMidiSeq *MidiSeqPtr;

typedef struct TMidiSeq
{
    MidiEvPtr first;   /* first event pointer */
    MidiEvPtr last;    /* last event pointer  */
    Ptr undef1;
    Ptr undef2;
} TMidiSeq;



FilterPtr

typedef struct TFilter *FilterPtr;

typedef struct TFilter
{
    char port[32];      /* 256 bits */
    char evType[32];    /* 256 bits */
    char channel[2];    /*  16 bits */
    char unused[2];     /*  16 bits */
} TFilter;



SyncInfoPtr

typedef struct TSyncInfo *SyncInfoPtr;

typedef struct TSyncInfo
{
    long        time;
    long        reenter;
    unsigned short syncMode;
    Byte        syncLocked;
    Byte        syncPort;
    long        syncStart;
    long        syncStop;
    long        syncOffset;
    long        syncSpeed;
    long        syncBreaks;
    short       syncFormat;
} TSyncInfo;



SmpteLocPtr

typedef struct TSmpteLocation *SmpteLocPtr;

typedef struct TSmpteLocation
{
    short format;    // (0:24f/s, 1:25f/s, 2:30DFf/s, 3:30f/s)
    short hours;     // 0..23
    short minutes;   // 0..59
    short seconds;   // 0..59
    short frames;    // 0..30 (according to format)
    short fracs;     // 0..99 (1/100 of frames)
} TSmpteLocation;


-eof